1 Introduction

This notebook contains the data analysis for the charts and numbers used on our site, CBFC.WATCH. To ensure full transparency with our readers, we are publishing our methodology and the R code used to generate the statistics for various parts of the site, as well as to provide a starting point for others who may be curious about how to use the data.

We explore these questions:

  1. Do some regional CBFC offices require more modifications than others?
  2. How have the primary reasons for censorship (e.g., violence, profanity, sexual content) trended over time?
  3. How much footage is typically removed from a film?
  4. Which specific censorship categories are becoming more frequent, and which are declining?
  5. What specific words and themes are most associated with each major censorship category?
  6. Which specific films have had the most footage removed by each regional office?

1.1 Data Loading and Preparation

Importing the dataset, correcting data types, and standardizing categorical information like language and regional office names.

data <- read_csv("https://github.com/diagram-chasing/censor-board-cuts/raw/refs/heads/master/data/data.csv", 
                 col_types = cols(.default = "c")) %>%
  mutate(
    cert_date = as.Date(cert_date),
    total_modified_time_secs = as.numeric(total_modified_time_secs),
    deleted_secs = as.numeric(deleted_secs),
    replaced_secs = as.numeric(replaced_secs),
    inserted_secs = as.numeric(inserted_secs)
  ) %>%
  # The 'certifier' column contains a string like "Examining Committee, Mumbai".
  # We extract the regional office name by splitting the string by the comma
  # and taking the last element.
  mutate(
    office = str_split(certifier, ",") %>%
      map_chr(last) %>%
      str_trim()
  ) %>%
  separate_rows(ai_content_types, sep = "\\|") %>%
  mutate(ai_content_types = str_trim(ai_content_types)) %>%
  # Filter out any rows where the content type is empty after separation.
  filter(ai_content_types != "") %>%
  # Standardize language names to correct for typos and variations in the raw data
  mutate(
    language = case_when(
      language == "Oriya" ~ "Odia",
      language == "Gujrati" ~ "Gujarati",
      language == "Chhatisgarhi" ~ "Chhattisgarhi",
      language == "Hariyanvi" ~ "Haryanvi",
      language == "Hindi Dub" ~ "Hindi Dubbed",
      TRUE ~ language
    )
  ) %>%
  filter(!is.na(language))

1.2 Exploratory Data Analysis

1.2.1 Languages in the Dataset

Counting how many films for each language in the dataset. We’ll show the top ones.

films_by_language_data <- data %>%
  distinct(id, language) %>%
  count(language, sort = TRUE) %>%
  top_n(10, n) %>%
  mutate(language = fct_reorder(language, n))

# write_json(films_by_language_data, "films_by_language.json", pretty = TRUE, auto_unbox = TRUE)

films_by_language_data %>%
  ggplot(aes(x = n, y = language)) +
  geom_col(fill = tertiary_color, alpha = 0.9) +
  geom_text(aes(label = comma(n)), hjust = -0.15, size = 3.5, color = "gray20") +
  scale_x_continuous(
    labels = comma,
    expand = expansion(mult = c(0, 0.12))
  ) +
  labs(
    title = "Top 15 Languages by Number of Films Censored",
    subtitle = "Hindi, Telugu, and Tamil are the languages with the most films",
    x = "Number of Unique Films",
    y = NULL
  ) +
  theme_cbfc()

1.2.2 Reasons for Modification

The most common reasons for modifications, based on the AI-classified content types.

mods_by_content_data <- data %>%
  filter(!is.na(ai_content_types)) %>%
  count(ai_content_types, sort = TRUE) %>%
  top_n(15, n) %>%
  mutate(
    pretty_name = str_replace_all(ai_content_types, "_", " ") %>% str_to_title(),
    pretty_name = fct_reorder(pretty_name, n)
  )

write_json(mods_by_content_data, "modifications_by_content.json", pretty = TRUE, auto_unbox = TRUE)

mods_by_content_data %>%
  ggplot(aes(x = n, y = pretty_name)) +
  geom_col(fill = secondary_color, alpha = 0.9) +
  geom_text(aes(label = comma(n)), hjust = -0.15, size = 3, color = "gray20") +
  scale_x_continuous(
    labels = comma,
    expand = expansion(mult = c(0, 0.1))
  ) +
  labs(
    title = "Most Common Reasons for Film Modifications",
    x = "Number of Modifications",
    y = "Content Category"
  ) +
  theme_cbfc()

1.2.3 Duration of Edits by Action

We’ve classified each modification log into verbs depending on what action was taken. For example, adding a smoking disclaimer might be an ‘Insertion’ but removing an entire scene is ‘Deletion’. There are also replacements, audio modifications, visual modifications (such as blurs), and so on. We can look at the general distribution for each of these edits.

duration_summary <- data %>%
  filter(total_modified_time_secs > 0, !is.na(ai_action)) %>%
  group_by(ai_action) %>%
  summarise(
    min = min(total_modified_time_secs, na.rm = TRUE),
    q1 = quantile(total_modified_time_secs, 0.25, na.rm = TRUE),
    median = median(total_modified_time_secs, na.rm = TRUE),
    q3 = quantile(total_modified_time_secs, 0.75, na.rm = TRUE),
    max = max(total_modified_time_secs, na.rm = TRUE),
    count = n(),
    .groups = 'drop'
  ) %>%
  mutate(pretty_name = str_replace_all(ai_action, "_", " ") %>% str_to_title()) %>%
  arrange(median)


# Export sample of raw data for BoxX component
duration_boxplot_data <- data %>%
   filter(
    total_modified_time_secs > 0, 
    total_modified_time_secs < 1400, # Found that anything above this is mostly incorrectly entered data
    !is.na(ai_action),
    ai_action != 'content_overlay',
    movie_name != 'ARISHADVARGA' # this movie clearly has a data processing error where the times are added cumulatively https://archive.org/details/cbfc-ecinepramaan-100020292100000261
  ) %>%
  mutate(pretty_name = str_replace_all(ai_action, "_", " ") %>% str_to_title()) %>%
  group_by(ai_action, pretty_name) %>%
  # Sample up to 500 points. If a group has < 500 points, it will take all of them.
  slice_sample(n = 500) %>%
  ungroup() %>%
  select(
    action = ai_action,
    category = pretty_name, 
    duration = total_modified_time_secs
  )


write_json(duration_summary, "duration_by_action_summary.json", pretty = TRUE, auto_unbox = TRUE)
write_json(duration_boxplot_data, "duration_by_action_boxplot.json", pretty = TRUE, auto_unbox = TRUE)

  duration_boxplot_data %>% 
  ggplot(aes(
    x = fct_reorder(category, duration, .fun = median),
    y = duration,
    fill = category
  )) +
  geom_boxplot(show.legend = FALSE, alpha = 0.8, fill = wes_colors[3]) +
  scale_y_log10(
    breaks = c(1, 10, 60, 300, 1800),
    labels = c("1 sec", "10 secs", "1 min", "5 mins", "30 mins")
  ) +
  coord_flip() +
  labs(
    title = "How Long are Different Types of Edits?",
    subtitle = "Distribution of modification durations for each action type on a logarithmic scale.",
    x = NULL,
    y = "Duration of Modification"
  ) +
  theme_cbfc()

1.3 Modification Reasons by Movie Rating

The dataset includes tags for what reason a particular modification was made; violence, profanity and so on. While I have a pretty good idea of what this will give, we can see what is the breakdown of each reason by the rating for that movie (rating is the U, UA, A classification for who can watch the movie).

rating_breakdown <- data %>%
  filter(rating %in% c("U", "UA", "A"), !is.na(ai_content_types)) %>%
  mutate(content_category = case_when(
    ai_content_types %in% c("sexual_explicit", "sexual_suggestive") ~ "Sexual Content",
    ai_content_types == "profanity" ~ "Profanity",
    ai_content_types == "violence" ~ "Violence",
    ai_content_types == "substance" ~ "Substance Use",
    ai_content_types == "religious" ~ "Religious Content",
    ai_content_types == "political" ~ "Political Content",
    TRUE ~ "Other"
  )) %>%
  count(rating, content_category, name = "modification_count", sort = TRUE) %>%
  group_by(rating) %>%
  mutate(percentage = modification_count / sum(modification_count)) %>%
  ungroup()

common_types <- rating_breakdown %>%
  filter(content_category != "Other") %>%
  group_by(content_category) %>%
  summarise(total = sum(modification_count), .groups = 'drop') %>%
  pull(content_category)

rating_breakdown %>%
  filter(content_category %in% common_types) %>%
  ggplot(aes(
    x = percentage,
    y = fct_reorder(content_category, percentage, .desc = FALSE),
    fill = rating
  )) +
  geom_col(color = "white", linewidth = 0.5) +
  facet_wrap(~rating, scales = "free_y", ncol = 3) +
  scale_x_continuous(labels = percent_format(accuracy = 1)) +
  scale_fill_manual(
    values = c("U" = wes_colors[1], "UA" = wes_colors[2], "A" = wes_colors[3])
  ) +
  labs(
    title = "Censorship reasons by film rating",
    subtitle = "Proportional breakdown of modification reasons within each film rating category.",
    x = "% of all modifications for this rating",
    y = NULL
  ) +
  theme_cbfc() +
  theme(
    strip.text = element_text(size = 14, face = "bold", color = "gray20", margin = margin(t = 5, b = 10)),
    strip.background = element_blank(),
    panel.grid.major.x = element_line(color = "gray90", linetype = "dotted"),
    panel.spacing.x = unit(2, "lines"),
    legend.position = "none"
  )

write_json(rating_breakdown, "rating_breakdown.json", pretty = TRUE, auto_unbox = TRUE)

1.4 Average Cut Time by Regional Office

Different regional offices of the CBFC may apply censorship standards differently. Here, we calculate the average total time modified per film for each major office. We filter out extreme outliers (films with more than 30 minutes of cuts) and only include offices that have certified a sufficient number of films (at least 50).

film_summary <- data %>%
  filter(!is.na(office) & !str_detect(office, "\\.mp4$")) %>%
  group_by(id, movie_name, office) %>%
  summarise(
    total_secs = sum(total_modified_time_secs, na.rm = TRUE),
    .groups = 'drop'
  ) %>%
  filter(total_secs > 0, total_secs < 1800)

office_stats <- film_summary %>%
  group_by(office) %>%
  filter(n() >= 50) %>%
  summarise(
    film_count = n(),
    mean_total_secs = mean(total_secs, na.rm = TRUE),
    se = sd(total_secs, na.rm = TRUE) / sqrt(n()),
    ci_lower_secs = pmax(0, mean_total_secs - 1.96 * se),
    ci_upper_secs = mean_total_secs + 1.96 * se,
    .groups = 'drop'
  ) %>%
  arrange(desc(mean_total_secs))

write_json(office_stats, "cuts_by_office.json", pretty = TRUE, auto_unbox = TRUE)

summary_table <- office_stats %>%
  mutate(
    `Average Time` = format_seconds(mean_total_secs),
    `95% CI Lower` = format_seconds(ci_lower_secs),
    `95% CI Upper` = format_seconds(ci_upper_secs)
  ) %>%
  select(
    Office = office,
    `Films Analyzed` = film_count,
    `Average Time`,
    `95% CI Lower`,
    `95% CI Upper`
  )

summary_table %>%
  gt() %>%
  tab_header(
    title = "Average Modification Time per Film by CBFC Regional Office",
    subtitle = "Analysis of offices with at least 50 certified films"
  ) %>%
  tab_style(
    style = list(
      cell_fill(color = wes_colors[1], alpha = 0.3),
      cell_text(weight = "bold")
    ),
    locations = cells_column_labels()
  ) %>%
  tab_style(
    style = cell_text(align = "center"),
    locations = cells_body(columns = c(`Films Analyzed`, `Average Time`, `95% CI Lower`, `95% CI Upper`))
  ) %>%
  cols_align(
    align = "left",
    columns = Office
  ) %>%
  tab_options(
    table.font.names = "Atkinson Hyperlegible",
    heading.title.font.size = 16,
    heading.subtitle.font.size = 12,
    column_labels.font.size = 12,
    table.font.size = 11
  )
Average Modification Time per Film by CBFC Regional Office
Analysis of offices with at least 50 certified films
Office Films Analyzed Average Time 95% CI Lower 95% CI Upper
Chennai 1458 2m 46s 2m 33s 2m 59s
Thiruvananthpuram 607 2m 45s 2m 26s 3m 04s
Delhi 309 2m 20s 1m 57s 2m 43s
Mumbai 4192 2m 17s 2m 11s 2m 22s
Bangalore 773 1m 36s 1m 24s 1m 47s
Kolkata 133 1m 35s 1m 14s 1m 56s
Hyderabad 849 1m 34s 1m 24s 1m 45s

1.6 Distribution of Modification Durations

This histogram shows the distribution of total modification times for films that had at least one cut. Approximately half of the films in the dataset have ‘zero seconds’ of edits (meaning modifications might have been made but they were not logged with a duration of edit); this chart focuses only on those that have duration values.

film_data <- data %>%
  group_by(id) %>%
  summarise(
    total_modified_time_secs = sum(total_modified_time_secs, na.rm = TRUE),
    .groups = 'drop'
  )

total_films <- nrow(film_data)
percent_zero <- mean(film_data$total_modified_time_secs == 0, na.rm = TRUE)
film_data_positive <- film_data %>% filter(total_modified_time_secs > 0)
median_val_positive <- median(film_data_positive$total_modified_time_secs)

p_dist <- ggplot(film_data_positive, aes(x = total_modified_time_secs)) +
  geom_histogram(
    aes(y = after_stat(count) / total_films * 100),
    fill = wes_colors[2],
    bins = 40,
    boundary = 0
  ) +
  geom_vline(
    xintercept = median_val_positive,
    linetype = "dashed",
    color = "gray20",
    linewidth = 0.8
  ) +
  # Use a log10 scale on the x-axis because the data is highly skewed.
  scale_x_log10(
    breaks = c(1, 10, 60, 300, 1800),
    labels = c("1s", "10s", "1m", "5m", "30m")
  ) +
  scale_y_continuous(
    expand = expansion(mult = c(0, 0.05)),
    labels = percent_format(scale = 1)
  ) +
  labs(
    title = "Distribution of Modification Times",
    subtitle = str_glue("Comparing total modification time for films with at least one cut.
                        This chart excludes the {percent(percent_zero, accuracy=1)} of films with zero modifications."),
    x = "Total Modification Time (Logarithmic Scale)",
    y = "Percent of All Films"
  ) +
  theme_cbfc() +
  theme(
    panel.grid.major.x = element_blank()
  )

print(p_dist)

# Export the data used for the histogram to a JSON file.
# We use ggplot_build() to extract the computed data from the plot object.
hist_data_for_export <- ggplot_build(p_dist)$data[[1]] %>%
  select(x_min = xmin, x_max = xmax, count, y_percent_total = y)

export_data_dist <- list(
  histogram_bins = hist_data_for_export,
  statistics = list(
    median_positive_secs = median_val_positive,
    total_films = total_films,
    percent_zero_mods = percent_zero
  ),
  axis_config = list(
    breaks = c(1, 10, 60, 300, 1800),
    labels = c("1s", "10s", "1m", "5m", "30m")
  )
)

write_json(export_data_dist, "histogram_data.json", pretty = TRUE, auto_unbox = TRUE)

1.8 Keyword Co-occurrence Network

This analysis explores which terms tend to appear together within the same film’s modification records.

We calculate the pairwise correlation between the 50 most common keywords and visualize the results as a network graph.

This contains a lot of NSFW stuff, but hiding it would…probably defeat the point.

reference_words <- data %>%
  filter(!is.na(ai_reference)) %>%
  mutate(word = str_split(tolower(ai_reference), "\\|")) %>%
  unnest(word) %>%
  filter(!is.na(word), !str_detect(word, "violence|scene|visual|dialogue")) %>%
  select(id, word)

word_counts <- reference_words %>%
  count(word, sort = TRUE)

word_pairs <- reference_words %>%
  filter(word %in% (word_counts %>% top_n(50, n) %>% pull(word))) %>%
  pairwise_cor(item = word, feature = id, sort = TRUE)

word_pairs %>%
  filter(correlation > 0.05) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
  geom_edge_link(aes(edge_alpha = correlation), show.legend = FALSE) +
  geom_node_point(color = wes_colors[3], size = 5) +
  geom_node_text(aes(label = name), repel = TRUE) +
  theme_void() +
  labs(
    title = "Which Censorship Terms Appear Together?",
    subtitle = "Co-occurrence network of the 50 most common keywords in CBFC modification records."
  )

# Export co-occurrence network data
network_export <- list(
  word_counts = word_counts %>% top_n(50, n),
  word_pairs = word_pairs %>% filter(correlation > 0.05)
)
write_json(network_export, "keyword_network.json", pretty = TRUE, auto_unbox = TRUE)

1.9 Most Important Keywords by Category (TF-IDF)

While the network graph shows which words co-occur, it doesn’t tell us which words are most characteristic of a specific censorship category. For that, we use a metric called Term Frequency-Inverse Document Frequency (TF-IDF).

TF-IDF identifies words that are common within one category (e.g., “blood” in the “violence” category) but are relatively rare in all other categories.

reference_tokens <- data %>%
  filter(!is.na(ai_reference), !is.na(ai_content_types)) %>%
  select(ai_content_types, ai_reference) %>%
  mutate(word = str_split(tolower(ai_reference), "\\|")) %>%
  unnest(word) %>%
  filter(word != "")

reference_tfidf <- reference_tokens %>%
  count(ai_content_types, word, sort = TRUE) %>%
  bind_tf_idf(term = word, document = ai_content_types, n = n) %>%
  arrange(desc(tf_idf))

top_terms_table <- reference_tfidf %>%
  group_by(ai_content_types) %>%
  slice_max(order_by = tf_idf, n = 5) %>%
  ungroup() %>%
  select(Category = ai_content_types, Term = word, `TF-IDF` = tf_idf) %>%
  filter(Category %in% c("violence", "profanity", "sexual_suggestive", "substance", "political", "religious"))

top_terms_table %>%
  gt() %>%
  tab_header(
    title = "Most Distinctive Keywords by Censorship Category",
    subtitle = "Using Term Frequency-Inverse Document Frequency (TF-IDF) analysis"
  ) %>%
  fmt_number(
    columns = `TF-IDF`,
    decimals = 3
  ) %>%
  tab_style(
    style = list(
      cell_fill(color = wes_colors[2], alpha = 0.3),
      cell_text(weight = "bold")
    ),
    locations = cells_column_labels()
  ) %>%
  tab_style(
    style = cell_text(transform = "capitalize"),
    locations = cells_body(columns = Category)
  ) %>%
  tab_style(
    style = cell_text(style = "italic"),
    locations = cells_body(columns = Term)
  ) %>%
  cols_align(
    align = "center",
    columns = `TF-IDF`
  ) %>%
  tab_options(
    table.font.names = "Atkinson Hyperlegible",
    heading.title.font.size = 16,
    heading.subtitle.font.size = 12,
    column_labels.font.size = 12,
    table.font.size = 11,
    row_group.font.weight = "bold"
  )
Most Distinctive Keywords by Censorship Category
Using Term Frequency-Inverse Document Frequency (TF-IDF) analysis
Category Term TF-IDF
political national flag 0.020
political modi 0.015
political indian flag 0.009
political pakistan 0.007
political political leaders 0.007
profanity munda 0.005
profanity bhenchod 0.004
profanity iththa 0.003
profanity bhadkov 0.003
profanity maal 0.003
religious superstition 0.044
religious black magic 0.015
religious religion 0.014
religious superstitions 0.012
religious religious sentiments 0.011
sexual_suggestive kissing scene 0.022
sexual_suggestive cleavage 0.019
sexual_suggestive sexual_suggestive 0.018
sexual_suggestive kissing 0.017
sexual_suggestive love making scene 0.017
substance tobacco 0.028
substance liquor label 0.017
substance akshay kumar 0.016
substance liquor labels 0.015
substance rahul dravid 0.014
violence blood 0.032
violence bloodshed 0.009
violence killing scene 0.007
violence dead bodies 0.007
violence dead body 0.006
write_json(reference_tfidf %>% slice_head(n = 300), "tfidf_analysis.json", pretty = TRUE, auto_unbox = TRUE)

1.10 Top Censored Films by Office

Identifies the top films that had the most time removed by each major CBFC regional office.

film_level_summary <- data %>%
  filter(!is.na(office) & !str_detect(office, "\\.mp4$")) %>%
  group_by(id, movie_name, office, language, cert_date, cert_no) %>%
  summarise(
    total_cuts = n(),
    total_time_removed_secs = sum(total_modified_time_secs, na.rm = TRUE),
    .groups = 'drop'
  ) %>%
  filter(total_time_removed_secs > 0, total_time_removed_secs < 1800) %>%
  mutate(
    year = map2_dbl(cert_date, cert_no, ~ extract_year(.x, .y)),
    cleaned_name = map_chr(movie_name, clean_name),
    slug = map2_chr(cleaned_name, year, make_slug)
  )

top_censored_by_office <- film_level_summary %>%
  group_by(office) %>%
  arrange(desc(total_time_removed_secs)) %>%
  slice_head(n = 10) %>%
  ungroup() %>%
  mutate(
    duration_formatted = format_seconds(total_time_removed_secs)
  ) %>%
  arrange(office, desc(total_time_removed_secs)) %>%
  select(Office = office, Language = language, `Film Name` = cleaned_name, 
         `Time Removed` = duration_formatted, `Total Cuts` = total_cuts, Slug = slug)

display_table <- top_censored_by_office %>%
  select(-Slug)

display_table %>%
  gt() %>%
  tab_header(
    title = "Top 10 Most Censored Films by Time Removed",
    subtitle = "Films with the highest modification times for each regional office"
  ) %>%
  tab_style(
    style = list(
      cell_fill(color = wes_colors[3], alpha = 0.3),
      cell_text(weight = "bold")
    ),
    locations = cells_column_labels()
  ) %>%
  tab_style(
    style = cell_text(style = "italic"),
    locations = cells_body(columns = `Film Name`)
  ) %>%
  cols_align(
    align = "center",
    columns = c(Language, `Time Removed`, `Total Cuts`)
  ) %>%
  cols_align(
    align = "left",
    columns = c(Office, `Film Name`)
  ) %>%
  tab_options(
    table.font.names = "Atkinson Hyperlegible",
    heading.title.font.size = 16,
    heading.subtitle.font.size = 12,
    column_labels.font.size = 12,
    table.font.size = 11
  ) %>%
  tab_style(
    style = cell_borders(
      sides = c("top", "bottom"),
      color = "lightgray",
      weight = px(1)
    ),
    locations = cells_body()
  )
Top 10 Most Censored Films by Time Removed
Films with the highest modification times for each regional office
Office Language Film Name Time Removed Total Cuts
Bangalore Kannada NEGILA ODEYA 26m 22s 3
Bangalore Hindi REHNA NAHI BIN TERE 23m 02s 1
Bangalore Kannada TIGER GALLI 19m 45s 128
Bangalore Kannada THUGS OF RAMAGHADA 19m 42s 19
Bangalore Kannada M E S T R I (REVISED) 18m 20s 21
Bangalore Kannada YAAR YAARO GHORIMELE 15m 09s 58
Bangalore Kannada MARKATA 15m 08s 6
Bangalore Kannada ROYAL MECH 14m 22s 2
Bangalore Kannada BENGALURU UNDERWORLD 12m 18s 75
Bangalore Kannada YOGI DUNIYA (REVISED) 11m 19s 28
Chennai Tamil IDHU ENGA BHOOMI (RE-REVISED) 27m 32s 33
Chennai Telugu PULIDEBBA (REVISED) 24m 44s 17
Chennai Tamil 'AALAPIRANTHAVAN' (REVISED) 24m 22s 25
Chennai Tamil NERAM NALLA NERAM (REVISED) 24m 07s 23
Chennai Tamil NAAN UNNA NINACHEN (REVISED) 23m 35s 25
Chennai Tamil THEEVIRAM 22m 43s 6
Chennai Telugu DEBBAKU DEBBA (REVISED) 22m 07s 12
Chennai Telugu DARJA DONGA (REVISED) 22m 05s 15
Chennai Telugu BANDIPOTU SIMHAM (REVISED) 21m 47s 21
Chennai Telugu KONDAVEETI SIVA (REVISED) 21m 05s 23
Cuttack Odia TU MO SWEET SIXTEEN 8m 00s 3
Cuttack Hindi " YEH KAISA TIGDAM " 6m 50s 7
Cuttack Odia PADIGALI TO PREMARE 5m 57s 9
Cuttack Bhojpuri V I P 2 4m 58s 1
Cuttack Chhattisgarhi SUPER HERO BHAISHA 4m 40s 4
Cuttack Bhojpuri IDDARAMMAYILATHO 4m 12s 1
Cuttack Odia SUPER RAKSHAK 4m 00s 2
Cuttack Hindi CHOR CHOR 3m 31s 13
Cuttack Hindi MANTHRA 3m 09s 1
Cuttack Odia JOUTHI TU SEITHI MU 2m 56s 6
Delhi Hindi MISUSE 27m 39s 3
Delhi Hindi FADFADAA 25m 38s 21
Delhi Bhojpuri DHOOM MACHAIELA RAJAJEE 15m 55s 19
Delhi Odia SATYAM 15m 54s 1
Delhi Hindi AAG AUR TEZAAB 15m 41s 9
Delhi Hindi AAKHIRI RAAT 14m 42s 25
Delhi Hindi TOPLESS 14m 08s 17
Delhi Hindi MAIN HOON SHERNI 11m 51s 17
Delhi Punjabi PAUNE 9 11m 34s 14
Delhi Hindi FUNTASIYAN 11m 00s 2
Guwahati Hindi CAPITAL 3m 00s 5
Guwahati Bodo BEKAR ROMEO 1m 38s 4
Guwahati Hindi Dubbed BARUN RAI AND THE HOUSE ON THE CLIFF 1m 34s 10
Guwahati Assamese RAKSHAK - THE SAVIOUR 1m 08s 3
Guwahati Assamese BAD BOYS 0m 50s 2
Guwahati Assamese RONGATAPU 1982 0m 32s 3
Guwahati Hindi KOOKI 0m 24s 5
Guwahati Khasi KYNJAH 0m 23s 6
Guwahati Manipuri NGAMNABA LANFAMSE 0m 22s 1
Guwahati Assamese THE SLAM BOOK 0m 17s 4
Hyderabad Telugu JUNIORS 24m 00s 46
Hyderabad Telugu ALLUDA MAJAAKAA 20m 18s 28
Hyderabad Telugu 1948 AKHANDA BHARATH 16m 11s 18
Hyderabad Telugu "NARAKASURA" 15m 55s 10
Hyderabad Telugu NANI 15m 50s 25
Hyderabad Malayalam SIMHA MUGHAM 14m 25s 18
Hyderabad Telugu LAAL SALAAM 14m 15s 25
Hyderabad Telugu "NAYEEM DIARIES" (A TO UA) 13m 28s 25
Hyderabad Telugu VIKKI DADA 13m 07s 22
Hyderabad Telugu "OREY RIKSHAW" (A TO UA) 12m 54s 24
Kolkata Bengali MAAHIYA (REVISED) 13m 23s 11
Kolkata Hindi PYAR SE PYAR TAK (REVISED) 9m 02s 7
Kolkata Bengali CIRCLE (REVISED) 8m 34s 18
Kolkata Bengali ROMANTIC NOY ( REVISED) 7m 27s 31
Kolkata Bengali MAHANAYAK UTTAM KUMAR ( THE METRO STATION ) ( REVISED) 6m 34s 5
Kolkata Bengali CHOCOLATE(REVISED) 6m 24s 22
Kolkata Bengali ANGAAR (REVISED) 6m 02s 33
Kolkata Bengali BIJOYA DASHAMI (REVISED) 5m 50s 18
Kolkata Bengali SURJO THE BOSS 5m 48s 3
Kolkata Bengali VIRUS-DEHER NOI...MONER ( REVISED) 4m 26s 15
Mumbai English VINCENT N ROXXY 29m 26s 28
Mumbai English BULLETPROOF 2 28m 02s 33
Mumbai Marathi NAY VARAN BHAAT LONCHA KON NAY KONCHA(REVISED) 25m 06s 17
Mumbai Bhojpuri JIDDI ASHIQUE 24m 47s 27
Mumbai Bhojpuri DAROGA BABUNI 24m 25s 25
Mumbai Hindi AKSAR - 2 23m 52s 7
Mumbai Hindi OMG 2 23m 33s 25
Mumbai Portugal CITY OF GOD 22m 47s 68
Mumbai Hindi BHAIRAVA GEETHA 21m 19s 40
Mumbai Bhojpuri BAA KEHU MAAI KE LAAL 21m 09s 7
Thiruvananthpuram Malayalam THANKAMANI 25m 25s 6
Thiruvananthpuram Malayalam ATTENTION PLEASE 22m 28s 3
Thiruvananthpuram Malayalam VIRAL 2020 22m 24s 2
Thiruvananthpuram Malayalam UDAL 21m 39s 69
Thiruvananthpuram Malayalam ARTHARAATHRI PANTHRANDU MUTHAL AARU VARE 21m 32s 3
Thiruvananthpuram Malayalam KARIMPULI (RE-REVISED) 20m 53s 15
Thiruvananthpuram Malayalam ARDHARAATHRI (REVISED) 20m 19s 18
Thiruvananthpuram Malayalam L 20m 06s 4
Thiruvananthpuram Malayalam BOOMERANG 19m 52s 2
Thiruvananthpuram Malayalam PRANAMAM 19m 19s 20
# Export top censored films data with slug included
write_json(top_censored_by_office, "top_censored_films.json", pretty = TRUE, auto_unbox = TRUE)

1.11 Further Information

For more details, interactive charts, and the full explorer, please visit our project website: https://cbfc.watch

The analysis was conducted by Aman Bhargava and Vivek Matthew for Diagram Chasing.

1.11.1 How to Cite

Bhargava, A., Matthew, V., & Diagram Chasing. (2025). Analyzing Film Censorship in India: CBFC Watch. Retrieved from https://cbfc.watch.

BibTeX Entry

For use in LaTeX documents, you can use the following BibTeX entry:

@misc{Bhargava2025CBFC,
  author = {Bhargava, Aman and Matthew, Vivek and {Diagram Chasing}},
  title  = {Analyzing Film Censorship in India: CBFC Watch},
  year   = {2025},
  month  = {September},
  howpublished = {\url{https://cbfc.watch}},
  note   = {Analysis and visualizations by Diagram Chasing. Last accessed: \today}
}
LS0tCnRpdGxlOiAiQW5hbHl6aW5nIEZpbG0gQ2Vuc29yc2hpcCBpbiBJbmRpYTogQ0JGQyBXYXRjaCIKYXV0aG9yOiAiQW5hbHlzaXMgYnkgQW1hbiBCaGFyZ2F2YSBhbmQgVml2ZWsgTWF0dGhldywgRGlhZ3JhbSBDaGFzaW5nIgpkYXRlOiAiVXBkYXRlZDogYHIgZm9ybWF0KFN5cy5EYXRlKCksICclQiAlZCwgJVknKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBmaWdfd2lkdGg6IDEwCiAgICBmaWdfaGVpZ2h0OiA2CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgc2VsZl9jb250YWluZWQ6IHRydWUKICAgIGtlZXBfbWQ6IGZhbHNlCmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCi0tLQoKPHN0eWxlPgpAaW1wb3J0IHVybCgnaHR0cHM6Ly9mb250cy5nb29nbGVhcGlzLmNvbS9jc3MyP2ZhbWlseT1BdGtpbnNvbitIeXBlcmxlZ2libGU6d2dodEA0MDA7NzAwJmRpc3BsYXk9c3dhcCcpOwoKYm9keSB7CiAgZm9udC1mYW1pbHk6ICdBdGtpbnNvbiBIeXBlcmxlZ2libGUnLCBzYW5zLXNlcmlmOwogIGJhY2tncm91bmQtY29sb3I6IHZhcigtLWNvbG9yLXNlcGlhKTsKICBjb2xvcjogdmFyKC0tY29sb3Itc2VwaWEtYnJvd24pOwogIGxpbmUtaGVpZ2h0OiAxLjY7CiAgbWF4LXdpZHRoOiAxMjAwcHg7CiAgbWFyZ2luOiAwIGF1dG87CiAgcGFkZGluZzogMnJlbTsKfQo8L3N0eWxlPgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkoem9vKQpsaWJyYXJ5KGpzb25saXRlKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHRpZHl0ZXh0KQpsaWJyYXJ5KHdpZHlyKQpsaWJyYXJ5KGlncmFwaCkKbGlicmFyeShnZ3JhcGgpCmxpYnJhcnkoYnJvb20pCmxpYnJhcnkoZm9yY2F0cykKbGlicmFyeSh3ZXNhbmRlcnNvbikKbGlicmFyeShndCkKCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvID0gVFJVRSwKICB3YXJuaW5nID0gRkFMU0UsCiAgbWVzc2FnZSA9IEZBTFNFLAogIGZpZy53aWR0aCA9IDEwLAogIGZpZy5oZWlnaHQgPSA2LAogIGRwaSA9IDMwMCwKICBvdXQud2lkdGggPSAiMTAwJSIKKQoKb3B0aW9ucyhzY2lwZW4gPSA5OTkpCgp3ZXNfY29sb3JzIDwtIHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMSIsIDgsIHR5cGUgPSAiY29udGludW91cyIpCnByaW1hcnlfY29sb3IgPC0gIiMzMTgyYmQiCnNlY29uZGFyeV9jb2xvciA8LSAiI2RlNzdhZSIKdGVydGlhcnlfY29sb3IgPC0gIiMyYzdmYjgiCgp0aGVtZV9jYmZjIDwtIGZ1bmN0aW9uKCkgewogIHRoZW1lX21pbmltYWwoYmFzZV9mYW1pbHkgPSAic2FucyIpICsKICAgIHRoZW1lKAogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNiwgbWFyZ2luID0gbWFyZ2luKGIgPSA4KSksCiAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExLCBjb2xvciA9ICJncmF5NDAiLCBtYXJnaW4gPSBtYXJnaW4oYiA9IDE1KSksCiAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgY29sb3IgPSAiZ3JheTQwIiksCiAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExLCBmYWNlID0gImJvbGQiLCBjb2xvciA9ICJncmF5MjAiKSwKICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMjAsIDI1LCAyMCwgMjUpCiAgICApCn0KCmNsZWFuX25hbWUgPC0gZnVuY3Rpb24obmFtZSkgewogIGlmIChpcy5uYShuYW1lKSB8fCBuYW1lID09ICIiKSByZXR1cm4oIiIpCiAgbmFtZSA8LSBzdHJfdHJpbShuYW1lKSAlPiUKICAgIHN0cl9yZXBsYWNlKCJbXFwuLCE/OzpdKyQiLCAiIikgJT4lCiAgICBzdHJfcmVwbGFjZSgiXltcXC4sIT87Ol0rIiwgIiIpICU+JQogICAgc3RyX3JlcGxhY2UoJ14iezIsM30oLis/KSJ7MiwzfSQnLCAiXFwxIikgJT4lCiAgICBzdHJfcmVwbGFjZSgiXicoLis/KSckIiwgIlxcMSIpICU+JQogICAgc3RyX3JlcGxhY2UoIlxcKiskIiwgIiIpICU+JQogICAgc3RyX3JlcGxhY2VfYWxsKCJcXHMrIiwgIiAiKQogIHN0cl90cmltKG5hbWUpCn0KCm1ha2Vfc2x1ZyA8LSBmdW5jdGlvbihuYW1lLCB5ZWFyKSB7CiAgaWYgKGlzLm5hKG5hbWUpIHx8IG5hbWUgPT0gIiIpIHJldHVybigidW5rbm93biIpCiAgc2x1ZyA8LSBjbGVhbl9uYW1lKG5hbWUpICU+JSAKICAgIHN0cl90b19sb3dlcigpICU+JQogICAgc3RyX3JlcGxhY2VfYWxsKCJbXlxcd1xccy1dIiwgIiIpICU+JQogICAgc3RyX3JlcGxhY2VfYWxsKCJbXFxzLV0rIiwgIi0iKSAlPiUKICAgIHN0cl9yZXBsYWNlX2FsbCgiXi0rfC0rJCIsICIiKQogIAogIGlmICghaXMubmEoeWVhcikgJiYgeWVhciAhPSAiIikgewogICAgcGFzdGUwKHNsdWcsICItIiwgeWVhcikKICB9IGVsc2UgewogICAgc2x1ZwogIH0KfQoKZXh0cmFjdF95ZWFyIDwtIGZ1bmN0aW9uKGNlcnRfZGF0ZSwgY2VydF9ubyA9IE5VTEwpIHsKICBpZiAoaXMubnVsbChjZXJ0X2RhdGUpKSBjZXJ0X2RhdGUgPC0gTkEKICBpZiAoaXMubnVsbChjZXJ0X25vKSkgY2VydF9ubyA8LSBOQQogIAogIGlmICghaXMubmEoY2VydF9kYXRlKSkgewogICAgY2VydF9kYXRlX3N0ciA8LSBhcy5jaGFyYWN0ZXIoY2VydF9kYXRlKQogICAgaWYgKGNlcnRfZGF0ZV9zdHIgIT0gIiIgJiYgY2VydF9kYXRlX3N0ciAhPSAiTkEiKSB7CiAgICAgIHRyeUNhdGNoKHsKICAgICAgICB5ZWFyX2Zyb21fZGF0ZSA8LSB5ZWFyKGFzLkRhdGUoY2VydF9kYXRlX3N0ciwgZm9ybWF0ID0gIiVZLSVtLSVkIikpCiAgICAgICAgaWYgKCFpcy5uYSh5ZWFyX2Zyb21fZGF0ZSkpIHJldHVybih5ZWFyX2Zyb21fZGF0ZSkKICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlKSB7fSkKICAgIH0KICB9CiAgCiAgaWYgKCFpcy5uYShjZXJ0X25vKSkgewogICAgY2VydF9ub19zdHIgPC0gYXMuY2hhcmFjdGVyKGNlcnRfbm8pCiAgICBpZiAoY2VydF9ub19zdHIgIT0gIiIgJiYgY2VydF9ub19zdHIgIT0gIk5BIikgewogICAgICB0cnlDYXRjaCh7CiAgICAgICAgcGFydHMgPC0gc3RyX3NwbGl0KGNlcnRfbm9fc3RyLCAiLSIpW1sxXV0KICAgICAgICBpZiAobGVuZ3RoKHBhcnRzKSA+PSAyKSB7CiAgICAgICAgICBiZWZvcmVfbGFzdCA8LSBwYXJ0c1tsZW5ndGgocGFydHMpIC0gMV0KICAgICAgICAgIHllYXJfbWF0Y2ggPC0gc3RyX2V4dHJhY3QoYmVmb3JlX2xhc3QsICJcXGR7NH0kIikKICAgICAgICAgIGlmICghaXMubmEoeWVhcl9tYXRjaCkpIHsKICAgICAgICAgICAgeWVhcl92YWwgPC0gYXMubnVtZXJpYyh5ZWFyX21hdGNoKQogICAgICAgICAgICBpZiAoeWVhcl92YWwgPj0gMTkwMCAmJiB5ZWFyX3ZhbCA8PSAyMDkwKSB7CiAgICAgICAgICAgICAgcmV0dXJuKHllYXJfdmFsKQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHt9KQogICAgfQogIH0KICAKICByZXR1cm4oTkFfcmVhbF8pCn0KCmZvcm1hdF9zZWNvbmRzIDwtIGZ1bmN0aW9uKHNlY3MpIHsKICBtaW51dGVzIDwtIGZsb29yKHNlY3MgLyA2MCkKICBzZWNvbmRzIDwtIHJvdW5kKHNlY3MgJSUgNjApCiAgcmV0dXJuKHNwcmludGYoIiVkbSAlMDJkcyIsIG1pbnV0ZXMsIHNlY29uZHMpKQp9CmBgYAoKIyBJbnRyb2R1Y3Rpb24KClRoaXMgbm90ZWJvb2sgY29udGFpbnMgdGhlIGRhdGEgYW5hbHlzaXMgZm9yIHRoZSBjaGFydHMgYW5kIG51bWJlcnMgdXNlZCBvbiBvdXIgc2l0ZSwgW0NCRkMuV0FUQ0hdKGh0dHBzOi8vY2JmYy53YXRjaCkuIFRvIGVuc3VyZSBmdWxsIHRyYW5zcGFyZW5jeSB3aXRoIG91ciByZWFkZXJzLCB3ZSBhcmUgcHVibGlzaGluZyBvdXIgbWV0aG9kb2xvZ3kgYW5kIHRoZSBSIGNvZGUgdXNlZCB0byBnZW5lcmF0ZSB0aGUgc3RhdGlzdGljcyBmb3IgdmFyaW91cyBwYXJ0cyBvZiB0aGUgc2l0ZSwgYXMgd2VsbCBhcyB0byBwcm92aWRlIGEgc3RhcnRpbmcgcG9pbnQgZm9yIG90aGVycyB3aG8gbWF5IGJlIGN1cmlvdXMgYWJvdXQgaG93IHRvIHVzZSB0aGUgZGF0YS4KCldlIGV4cGxvcmUgdGhlc2UgcXVlc3Rpb25zOgoKMS4gRG8gc29tZSByZWdpb25hbCBDQkZDIG9mZmljZXMgcmVxdWlyZSBtb3JlIG1vZGlmaWNhdGlvbnMgdGhhbiBvdGhlcnM/CjIuIEhvdyBoYXZlIHRoZSBwcmltYXJ5IHJlYXNvbnMgZm9yIGNlbnNvcnNoaXAgKGUuZy4sIHZpb2xlbmNlLCBwcm9mYW5pdHksIHNleHVhbCBjb250ZW50KSB0cmVuZGVkIG92ZXIgdGltZT8KMy4gSG93IG11Y2ggZm9vdGFnZSBpcyB0eXBpY2FsbHkgcmVtb3ZlZCBmcm9tIGEgZmlsbT8KNC4gV2hpY2ggc3BlY2lmaWMgY2Vuc29yc2hpcCBjYXRlZ29yaWVzIGFyZSBiZWNvbWluZyBtb3JlIGZyZXF1ZW50LCBhbmQgd2hpY2ggYXJlIGRlY2xpbmluZz8KNS4gV2hhdCBzcGVjaWZpYyB3b3JkcyBhbmQgdGhlbWVzIGFyZSBtb3N0IGFzc29jaWF0ZWQgd2l0aCBlYWNoIG1ham9yIGNlbnNvcnNoaXAgY2F0ZWdvcnk/CjYuIFdoaWNoIHNwZWNpZmljIGZpbG1zIGhhdmUgaGFkIHRoZSBtb3N0IGZvb3RhZ2UgcmVtb3ZlZCBieSBlYWNoIHJlZ2lvbmFsIG9mZmljZT8KCiMjIERhdGEgTG9hZGluZyBhbmQgUHJlcGFyYXRpb24KCkltcG9ydGluZyB0aGUgZGF0YXNldCwgY29ycmVjdGluZyBkYXRhIHR5cGVzLCBhbmQgc3RhbmRhcmRpemluZyBjYXRlZ29yaWNhbCBpbmZvcm1hdGlvbiBsaWtlIGxhbmd1YWdlIGFuZCByZWdpb25hbCBvZmZpY2UgbmFtZXMuCgpgYGB7ciBsb2FkLWFuZC1jbGVhbi1kYXRhfQpkYXRhIDwtIHJlYWRfY3N2KCJodHRwczovL2dpdGh1Yi5jb20vZGlhZ3JhbS1jaGFzaW5nL2NlbnNvci1ib2FyZC1jdXRzL3Jhdy9yZWZzL2hlYWRzL21hc3Rlci9kYXRhL2RhdGEuY3N2IiwgCiAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gY29scyguZGVmYXVsdCA9ICJjIikpICU+JQogIG11dGF0ZSgKICAgIGNlcnRfZGF0ZSA9IGFzLkRhdGUoY2VydF9kYXRlKSwKICAgIHRvdGFsX21vZGlmaWVkX3RpbWVfc2VjcyA9IGFzLm51bWVyaWModG90YWxfbW9kaWZpZWRfdGltZV9zZWNzKSwKICAgIGRlbGV0ZWRfc2VjcyA9IGFzLm51bWVyaWMoZGVsZXRlZF9zZWNzKSwKICAgIHJlcGxhY2VkX3NlY3MgPSBhcy5udW1lcmljKHJlcGxhY2VkX3NlY3MpLAogICAgaW5zZXJ0ZWRfc2VjcyA9IGFzLm51bWVyaWMoaW5zZXJ0ZWRfc2VjcykKICApICU+JQogICMgVGhlICdjZXJ0aWZpZXInIGNvbHVtbiBjb250YWlucyBhIHN0cmluZyBsaWtlICJFeGFtaW5pbmcgQ29tbWl0dGVlLCBNdW1iYWkiLgogICMgV2UgZXh0cmFjdCB0aGUgcmVnaW9uYWwgb2ZmaWNlIG5hbWUgYnkgc3BsaXR0aW5nIHRoZSBzdHJpbmcgYnkgdGhlIGNvbW1hCiAgIyBhbmQgdGFraW5nIHRoZSBsYXN0IGVsZW1lbnQuCiAgbXV0YXRlKAogICAgb2ZmaWNlID0gc3RyX3NwbGl0KGNlcnRpZmllciwgIiwiKSAlPiUKICAgICAgbWFwX2NocihsYXN0KSAlPiUKICAgICAgc3RyX3RyaW0oKQogICkgJT4lCiAgc2VwYXJhdGVfcm93cyhhaV9jb250ZW50X3R5cGVzLCBzZXAgPSAiXFx8IikgJT4lCiAgbXV0YXRlKGFpX2NvbnRlbnRfdHlwZXMgPSBzdHJfdHJpbShhaV9jb250ZW50X3R5cGVzKSkgJT4lCiAgIyBGaWx0ZXIgb3V0IGFueSByb3dzIHdoZXJlIHRoZSBjb250ZW50IHR5cGUgaXMgZW1wdHkgYWZ0ZXIgc2VwYXJhdGlvbi4KICBmaWx0ZXIoYWlfY29udGVudF90eXBlcyAhPSAiIikgJT4lCiAgIyBTdGFuZGFyZGl6ZSBsYW5ndWFnZSBuYW1lcyB0byBjb3JyZWN0IGZvciB0eXBvcyBhbmQgdmFyaWF0aW9ucyBpbiB0aGUgcmF3IGRhdGEKICBtdXRhdGUoCiAgICBsYW5ndWFnZSA9IGNhc2Vfd2hlbigKICAgICAgbGFuZ3VhZ2UgPT0gIk9yaXlhIiB+ICJPZGlhIiwKICAgICAgbGFuZ3VhZ2UgPT0gIkd1anJhdGkiIH4gIkd1amFyYXRpIiwKICAgICAgbGFuZ3VhZ2UgPT0gIkNoaGF0aXNnYXJoaSIgfiAiQ2hoYXR0aXNnYXJoaSIsCiAgICAgIGxhbmd1YWdlID09ICJIYXJpeWFudmkiIH4gIkhhcnlhbnZpIiwKICAgICAgbGFuZ3VhZ2UgPT0gIkhpbmRpIER1YiIgfiAiSGluZGkgRHViYmVkIiwKICAgICAgVFJVRSB+IGxhbmd1YWdlCiAgICApCiAgKSAlPiUKICBmaWx0ZXIoIWlzLm5hKGxhbmd1YWdlKSkKYGBgCgpgYGB7ciBvdXRwdXQtYmFkLXdvcmRzLCBpbmNsdWRlPUZBTFNFfQoKIyBQcm9jZXNzIHRoZSBhaV9yZWZlcmVuY2UgY29sdW1uIHRvIGZpbmQgdGhlIG1vc3QgY29tbW9uIHdvcmRzIHdlIGNhbiBibHVyIG91dCBvbiB0aGUgc2l0ZSBpbiBTRlcgbW9kZQojIEZvY3VzIG9uIHRoZSBtb3N0IG9mZmVuc2l2ZSBjYXRlZ29yaWVzOiBwcm9mYW5pdHkgYW5kIHNleHVhbCBjb250ZW50CmNvbW1vbl93b3Jkc190b19ibHVyIDwtIGRhdGEgJT4lCiAgZmlsdGVyKCFpcy5uYShhaV9yZWZlcmVuY2UpLCAKICAgICAgICAgYWlfY29udGVudF90eXBlcyAlaW4lIGMoInByb2Zhbml0eSIsICJzZXh1YWxfZXhwbGljaXQiLCAic2V4dWFsX3N1Z2dlc3RpdmUiKSkgJT4lCiAgbXV0YXRlKHdvcmQgPSBzdHJfc3BsaXQodG9sb3dlcihhaV9yZWZlcmVuY2UpLCAiXFx8IikpICU+JQogIHVubmVzdCh3b3JkKSAlPiUKICBmaWx0ZXIod29yZCAhPSAiIiwgCiAhd29yZCAlaW4lIGMoJ2FidXNlJywgJ2FjaWQnLCAnYWRpdHlhJywgJ2FsY29ob2wnLCAnYW1tYW4nLCAnYW1tYScsICdhbmphbGknLCAnYW5pdGhhJywgJ2FudXJhZGhhJywgJ2FyanVuJywgJ2FydW4nLCAnYXJ5YW4nLCAnYXNoYScsICdhdW50eScsICdiYWQgbGFuZ3VhZ2UnLCAnYmFkIHdvcmRzJywgJ2JhbmFuYScsICdiZWQnLCAnYmVlcicsICdiZWxseScsICdiaXQnLCAnYmxvb2QnLCAnYmxvdXNlJywgJ2JvZHknLCAnYm9tYicsICdib3knLCAnYm95cycsICdidW0nLCAnY2hlc3QnLCAnY2hyaXN0JywgJ2Nsb3RoZXMnLCAnY29jYWluZScsICdjb3VwbGUnLCAnY3JpbWUnLCAnY3VzcyB3b3JkJywgJ2RhbmNlJywgJ2RhbmNpbmcnLCAnZGFybGluZycsICdkZWFkIGJvZHknLCAnZGVyb2dhdG9yeSB3b3JkJywgJ2RpYWxvZ3VlJywgJ2RvZycsICdkb2xsJywgJ2RvbmdhJywgJ2RvdWJsZSBtZWFuaW5nJywgJ2RyZXNzJywgJ2RydWcnLCAnZHJ1Z3MnLCAnZWxpemFiZXRoJywgJ2Vuam95JywgJ2ZhY2UnLCAnZmlnaHQnLCAnZmlndXJlJywgJ2ZpbG0nLCAnZmluZ2VyJywgJ2ZvdWwgd29yZCcsICdmcmVzaCcsICdnYXknLCAnZ2VldGhhJywgJ2dob3N0JywgJ2dpcmwnLCAnZ2lybHMnLCAnZ29kJywgJ2dvcGknLCAnZ3VuJywgJ2hhbmQnLCAnaGFyYW0nLCAnaGVsbCcsICdoZXJvJywgJ2hlcm9pbicsICdoZXJvaW5lJywgJ2hvdCcsICdodWdnaW5nJywgJ2lkaW90JywgJ2luZGlhbicsICdpbmR1JywgJ2l0ZW0nLCAnaXRlbSBzb25nJywgJ2phaScsICdqYXlhbWFsaW5pJywgJ2plbm55JywgJ2plc3VzJywgJ2thc2knLCAna2lsbGluZycsICdraXJhbicsICdrcmlzaG5hJywgJ2t1bWFyJywgJ2xhZGtpJywgJ2xhZHknLCAnbGFkaWVzJywgJ2xha3NobWknLCAnbGVnJywgJ2xlZ3MnLCAnbGVzYmlhbicsICdsaXF1b3InLCAnbG92ZScsICdseXJpY3MnLCAnbWFhJywgJ21hbGxpa2EnLCAnbWFuJywgJ21hbmknLCAnbWFyaWp1YW5hJywgJ21hc3NhZ2UnLCAnbWF0dGVyJywgJ21lbicsICdtZW50YWwnLCAnbW9oYW4nLCAnbW9uZXknLCAnbW90aGVyJywgJ21vdmllJywgJ211cmRlcicsICdtdXNsaW0nLCAnbmFpbmEnLCAnbmF2ZWwnLCAnb2ZmJywgJ29ic2NlbmUgd29yZCcsICdwYW50JywgJ3BlcmlvZCcsICdwZXJzb24nLCAncGhvbmUnLCAncGllY2UnLCAncG9saWNlJywgJ3ByZWduYW50JywgJ3ByaXlhJywgJ3Byb2Zhbml0eScsICdwc3ljaG8nLCAncmFkaGEnLCAncmFnaHUnLCAncmFnaW5pJywgJ3JhamEnLCAncmFqdScsICdyYW11JywgJ3JhbXlhJywgJ3JhbmknLCAncmFzY2FsJywgJ3JhdmknLCAncmVraGEnLCAncm9tYW5jZScsICdyb21hbmNpbmcnLCAncm93ZHknLCAncnVtJywgJ3NhZCcsICdzYW50aGknLCAnc2FyZWUnLCAnc2NlbmUnLCAnc2V4dWFsX2V4cGxpY2l0JywgJ3NleHVhbF9zdWdnZXN0aXZlJywgJ3NoYWtlZWxhJywgJ3NoYW50aGknLCAnc2lkJywgJ3NpbGsgc21pdGhhJywgJ3Npc3RlcicsICdza2lydCcsICdzbGFwcGluZycsICdzbW9raW5nJywgJ3NvbicsICdzb25nJywgJ3N1bWF0aGknLCAnc3VubnkgbGVvbmUnLCAnc3VyeWEnLCAndGVhY2hlcicsICd0aGlnaCcsICd0aGlnaHMnLCAndG91Y2hpbmcnLCAndHJhbnNnZW5kZXInLCAndmFzdScsICd2aWpheScsICd2aWpqdScsICd2aWtyYW0nLCAndmlvbGVuY2UnLCAndmlzaG51JywgJ3Z1bGdhcicsICd3YWlzdCcsICd3aWZlJywgJ3dpbmUnLCAnd29tYW4nLCAnd29tZW4nLCAnd29yZCcsICd3b3JkcycsICd5b3UnKQogICkgJT4lCiAgY291bnQod29yZCwgc29ydCA9IFRSVUUpICU+JQogIHNsaWNlX2hlYWQobiA9IDUwMCkgJT4lIAogIHB1bGwod29yZCkKCndyaXRlX2pzb24oY29tbW9uX3dvcmRzX3RvX2JsdXIsICJiYWRfd29yZHMuanNvbiIsIHByZXR0eSA9IFRSVUUsIGF1dG9fdW5ib3ggPSBUUlVFKQoKYGBgCgojIyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzCgojIyMgTGFuZ3VhZ2VzIGluIHRoZSBEYXRhc2V0CgpDb3VudGluZyBob3cgbWFueSBmaWxtcyBmb3IgZWFjaCBsYW5ndWFnZSBpbiB0aGUgZGF0YXNldC4gV2UnbGwgc2hvdyB0aGUgdG9wIG9uZXMuCgpgYGB7ciBsYW5ndWFnZXMtY2hhcnR9CmZpbG1zX2J5X2xhbmd1YWdlX2RhdGEgPC0gZGF0YSAlPiUKICBkaXN0aW5jdChpZCwgbGFuZ3VhZ2UpICU+JQogIGNvdW50KGxhbmd1YWdlLCBzb3J0ID0gVFJVRSkgJT4lCiAgdG9wX24oMTAsIG4pICU+JQogIG11dGF0ZShsYW5ndWFnZSA9IGZjdF9yZW9yZGVyKGxhbmd1YWdlLCBuKSkKCiMgd3JpdGVfanNvbihmaWxtc19ieV9sYW5ndWFnZV9kYXRhLCAiZmlsbXNfYnlfbGFuZ3VhZ2UuanNvbiIsIHByZXR0eSA9IFRSVUUsIGF1dG9fdW5ib3ggPSBUUlVFKQoKZmlsbXNfYnlfbGFuZ3VhZ2VfZGF0YSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBuLCB5ID0gbGFuZ3VhZ2UpKSArCiAgZ2VvbV9jb2woZmlsbCA9IHRlcnRpYXJ5X2NvbG9yLCBhbHBoYSA9IDAuOSkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBjb21tYShuKSksIGhqdXN0ID0gLTAuMTUsIHNpemUgPSAzLjUsIGNvbG9yID0gImdyYXkyMCIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICBsYWJlbHMgPSBjb21tYSwKICAgIGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAwLjEyKSkKICApICsKICBsYWJzKAogICAgdGl0bGUgPSAiVG9wIDE1IExhbmd1YWdlcyBieSBOdW1iZXIgb2YgRmlsbXMgQ2Vuc29yZWQiLAogICAgc3VidGl0bGUgPSAiSGluZGksIFRlbHVndSwgYW5kIFRhbWlsIGFyZSB0aGUgbGFuZ3VhZ2VzIHdpdGggdGhlIG1vc3QgZmlsbXMiLAogICAgeCA9ICJOdW1iZXIgb2YgVW5pcXVlIEZpbG1zIiwKICAgIHkgPSBOVUxMCiAgKSArCiAgdGhlbWVfY2JmYygpCmBgYAoKIyMjIFJlYXNvbnMgZm9yIE1vZGlmaWNhdGlvbgoKVGhlIG1vc3QgY29tbW9uIHJlYXNvbnMgZm9yIG1vZGlmaWNhdGlvbnMsIGJhc2VkIG9uIHRoZSBBSS1jbGFzc2lmaWVkIGNvbnRlbnQgdHlwZXMuCgpgYGB7ciBtb2RpZmljYXRpb25zLWNoYXJ0fQptb2RzX2J5X2NvbnRlbnRfZGF0YSA8LSBkYXRhICU+JQogIGZpbHRlcighaXMubmEoYWlfY29udGVudF90eXBlcykpICU+JQogIGNvdW50KGFpX2NvbnRlbnRfdHlwZXMsIHNvcnQgPSBUUlVFKSAlPiUKICB0b3BfbigxNSwgbikgJT4lCiAgbXV0YXRlKAogICAgcHJldHR5X25hbWUgPSBzdHJfcmVwbGFjZV9hbGwoYWlfY29udGVudF90eXBlcywgIl8iLCAiICIpICU+JSBzdHJfdG9fdGl0bGUoKSwKICAgIHByZXR0eV9uYW1lID0gZmN0X3Jlb3JkZXIocHJldHR5X25hbWUsIG4pCiAgKQoKd3JpdGVfanNvbihtb2RzX2J5X2NvbnRlbnRfZGF0YSwgIm1vZGlmaWNhdGlvbnNfYnlfY29udGVudC5qc29uIiwgcHJldHR5ID0gVFJVRSwgYXV0b191bmJveCA9IFRSVUUpCgptb2RzX2J5X2NvbnRlbnRfZGF0YSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBuLCB5ID0gcHJldHR5X25hbWUpKSArCiAgZ2VvbV9jb2woZmlsbCA9IHNlY29uZGFyeV9jb2xvciwgYWxwaGEgPSAwLjkpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gY29tbWEobikpLCBoanVzdCA9IC0wLjE1LCBzaXplID0gMywgY29sb3IgPSAiZ3JheTIwIikgKwogIHNjYWxlX3hfY29udGludW91cygKICAgIGxhYmVscyA9IGNvbW1hLAogICAgZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIDAuMSkpCiAgKSArCiAgbGFicygKICAgIHRpdGxlID0gIk1vc3QgQ29tbW9uIFJlYXNvbnMgZm9yIEZpbG0gTW9kaWZpY2F0aW9ucyIsCiAgICB4ID0gIk51bWJlciBvZiBNb2RpZmljYXRpb25zIiwKICAgIHkgPSAiQ29udGVudCBDYXRlZ29yeSIKICApICsKICB0aGVtZV9jYmZjKCkKYGBgCgojIyMgRHVyYXRpb24gb2YgRWRpdHMgYnkgQWN0aW9uCgpXZSd2ZSBjbGFzc2lmaWVkIGVhY2ggbW9kaWZpY2F0aW9uIGxvZyBpbnRvIHZlcmJzIGRlcGVuZGluZyBvbiB3aGF0IGFjdGlvbiB3YXMgdGFrZW4uIEZvciBleGFtcGxlLCBhZGRpbmcgYSBzbW9raW5nIGRpc2NsYWltZXIgbWlnaHQgYmUgYW4gJ0luc2VydGlvbicgYnV0IHJlbW92aW5nIGFuIGVudGlyZSBzY2VuZSBpcyAnRGVsZXRpb24nLiBUaGVyZSBhcmUgYWxzbyByZXBsYWNlbWVudHMsIGF1ZGlvIG1vZGlmaWNhdGlvbnMsIHZpc3VhbCBtb2RpZmljYXRpb25zIChzdWNoIGFzIGJsdXJzKSwgYW5kIHNvIG9uLiBXZSBjYW4gbG9vayBhdCB0aGUgZ2VuZXJhbCBkaXN0cmlidXRpb24gZm9yIGVhY2ggb2YgdGhlc2UgZWRpdHMuCgpgYGB7ciBkdXJhdGlvbi1ib3hwbG90fQpkdXJhdGlvbl9zdW1tYXJ5IDwtIGRhdGEgJT4lCiAgZmlsdGVyKHRvdGFsX21vZGlmaWVkX3RpbWVfc2VjcyA+IDAsICFpcy5uYShhaV9hY3Rpb24pKSAlPiUKICBncm91cF9ieShhaV9hY3Rpb24pICU+JQogIHN1bW1hcmlzZSgKICAgIG1pbiA9IG1pbih0b3RhbF9tb2RpZmllZF90aW1lX3NlY3MsIG5hLnJtID0gVFJVRSksCiAgICBxMSA9IHF1YW50aWxlKHRvdGFsX21vZGlmaWVkX3RpbWVfc2VjcywgMC4yNSwgbmEucm0gPSBUUlVFKSwKICAgIG1lZGlhbiA9IG1lZGlhbih0b3RhbF9tb2RpZmllZF90aW1lX3NlY3MsIG5hLnJtID0gVFJVRSksCiAgICBxMyA9IHF1YW50aWxlKHRvdGFsX21vZGlmaWVkX3RpbWVfc2VjcywgMC43NSwgbmEucm0gPSBUUlVFKSwKICAgIG1heCA9IG1heCh0b3RhbF9tb2RpZmllZF90aW1lX3NlY3MsIG5hLnJtID0gVFJVRSksCiAgICBjb3VudCA9IG4oKSwKICAgIC5ncm91cHMgPSAnZHJvcCcKICApICU+JQogIG11dGF0ZShwcmV0dHlfbmFtZSA9IHN0cl9yZXBsYWNlX2FsbChhaV9hY3Rpb24sICJfIiwgIiAiKSAlPiUgc3RyX3RvX3RpdGxlKCkpICU+JQogIGFycmFuZ2UobWVkaWFuKQoKCiMgRXhwb3J0IHNhbXBsZSBvZiByYXcgZGF0YSBmb3IgQm94WCBjb21wb25lbnQKZHVyYXRpb25fYm94cGxvdF9kYXRhIDwtIGRhdGEgJT4lCiAgIGZpbHRlcigKICAgIHRvdGFsX21vZGlmaWVkX3RpbWVfc2VjcyA+IDAsIAogICAgdG90YWxfbW9kaWZpZWRfdGltZV9zZWNzIDwgMTQwMCwgIyBGb3VuZCB0aGF0IGFueXRoaW5nIGFib3ZlIHRoaXMgaXMgbW9zdGx5IGluY29ycmVjdGx5IGVudGVyZWQgZGF0YQogICAgIWlzLm5hKGFpX2FjdGlvbiksCiAgICBhaV9hY3Rpb24gIT0gJ2NvbnRlbnRfb3ZlcmxheScsCiAgICBtb3ZpZV9uYW1lICE9ICdBUklTSEFEVkFSR0EnICMgdGhpcyBtb3ZpZSBjbGVhcmx5IGhhcyBhIGRhdGEgcHJvY2Vzc2luZyBlcnJvciB3aGVyZSB0aGUgdGltZXMgYXJlIGFkZGVkIGN1bXVsYXRpdmVseSBodHRwczovL2FyY2hpdmUub3JnL2RldGFpbHMvY2JmYy1lY2luZXByYW1hYW4tMTAwMDIwMjkyMTAwMDAwMjYxCiAgKSAlPiUKICBtdXRhdGUocHJldHR5X25hbWUgPSBzdHJfcmVwbGFjZV9hbGwoYWlfYWN0aW9uLCAiXyIsICIgIikgJT4lIHN0cl90b190aXRsZSgpKSAlPiUKICBncm91cF9ieShhaV9hY3Rpb24sIHByZXR0eV9uYW1lKSAlPiUKICAjIFNhbXBsZSB1cCB0byA1MDAgcG9pbnRzLiBJZiBhIGdyb3VwIGhhcyA8IDUwMCBwb2ludHMsIGl0IHdpbGwgdGFrZSBhbGwgb2YgdGhlbS4KICBzbGljZV9zYW1wbGUobiA9IDUwMCkgJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdCgKICAgIGFjdGlvbiA9IGFpX2FjdGlvbiwKICAgIGNhdGVnb3J5ID0gcHJldHR5X25hbWUsIAogICAgZHVyYXRpb24gPSB0b3RhbF9tb2RpZmllZF90aW1lX3NlY3MKICApCgoKd3JpdGVfanNvbihkdXJhdGlvbl9zdW1tYXJ5LCAiZHVyYXRpb25fYnlfYWN0aW9uX3N1bW1hcnkuanNvbiIsIHByZXR0eSA9IFRSVUUsIGF1dG9fdW5ib3ggPSBUUlVFKQp3cml0ZV9qc29uKGR1cmF0aW9uX2JveHBsb3RfZGF0YSwgImR1cmF0aW9uX2J5X2FjdGlvbl9ib3hwbG90Lmpzb24iLCBwcmV0dHkgPSBUUlVFLCBhdXRvX3VuYm94ID0gVFJVRSkKCiAgZHVyYXRpb25fYm94cGxvdF9kYXRhICU+JSAKICBnZ3Bsb3QoYWVzKAogICAgeCA9IGZjdF9yZW9yZGVyKGNhdGVnb3J5LCBkdXJhdGlvbiwgLmZ1biA9IG1lZGlhbiksCiAgICB5ID0gZHVyYXRpb24sCiAgICBmaWxsID0gY2F0ZWdvcnkKICApKSArCiAgZ2VvbV9ib3hwbG90KHNob3cubGVnZW5kID0gRkFMU0UsIGFscGhhID0gMC44LCBmaWxsID0gd2VzX2NvbG9yc1szXSkgKwogIHNjYWxlX3lfbG9nMTAoCiAgICBicmVha3MgPSBjKDEsIDEwLCA2MCwgMzAwLCAxODAwKSwKICAgIGxhYmVscyA9IGMoIjEgc2VjIiwgIjEwIHNlY3MiLCAiMSBtaW4iLCAiNSBtaW5zIiwgIjMwIG1pbnMiKQogICkgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicygKICAgIHRpdGxlID0gIkhvdyBMb25nIGFyZSBEaWZmZXJlbnQgVHlwZXMgb2YgRWRpdHM/IiwKICAgIHN1YnRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBtb2RpZmljYXRpb24gZHVyYXRpb25zIGZvciBlYWNoIGFjdGlvbiB0eXBlIG9uIGEgbG9nYXJpdGhtaWMgc2NhbGUuIiwKICAgIHggPSBOVUxMLAogICAgeSA9ICJEdXJhdGlvbiBvZiBNb2RpZmljYXRpb24iCiAgKSArCiAgdGhlbWVfY2JmYygpCmBgYAoKIyMgTW9kaWZpY2F0aW9uIFJlYXNvbnMgYnkgTW92aWUgUmF0aW5nCgpUaGUgZGF0YXNldCBpbmNsdWRlcyB0YWdzIGZvciB3aGF0IHJlYXNvbiBhIHBhcnRpY3VsYXIgbW9kaWZpY2F0aW9uIHdhcyBtYWRlOyB2aW9sZW5jZSwgcHJvZmFuaXR5IGFuZCBzbyBvbi4gV2hpbGUgSSBoYXZlIGEgcHJldHR5IGdvb2QgaWRlYSBvZiB3aGF0IHRoaXMgd2lsbCBnaXZlLCB3ZSBjYW4gc2VlIHdoYXQgaXMgdGhlIGJyZWFrZG93biBvZiBlYWNoIHJlYXNvbiBieSB0aGUgcmF0aW5nIGZvciB0aGF0IG1vdmllIChyYXRpbmcgaXMgdGhlIGBVYCwgYFVBYCwgYEFgIGNsYXNzaWZpY2F0aW9uIGZvciB3aG8gY2FuIHdhdGNoIHRoZSBtb3ZpZSkuCgpgYGB7ciByYXRpbmctYnJlYWtkb3dufQpyYXRpbmdfYnJlYWtkb3duIDwtIGRhdGEgJT4lCiAgZmlsdGVyKHJhdGluZyAlaW4lIGMoIlUiLCAiVUEiLCAiQSIpLCAhaXMubmEoYWlfY29udGVudF90eXBlcykpICU+JQogIG11dGF0ZShjb250ZW50X2NhdGVnb3J5ID0gY2FzZV93aGVuKAogICAgYWlfY29udGVudF90eXBlcyAlaW4lIGMoInNleHVhbF9leHBsaWNpdCIsICJzZXh1YWxfc3VnZ2VzdGl2ZSIpIH4gIlNleHVhbCBDb250ZW50IiwKICAgIGFpX2NvbnRlbnRfdHlwZXMgPT0gInByb2Zhbml0eSIgfiAiUHJvZmFuaXR5IiwKICAgIGFpX2NvbnRlbnRfdHlwZXMgPT0gInZpb2xlbmNlIiB+ICJWaW9sZW5jZSIsCiAgICBhaV9jb250ZW50X3R5cGVzID09ICJzdWJzdGFuY2UiIH4gIlN1YnN0YW5jZSBVc2UiLAogICAgYWlfY29udGVudF90eXBlcyA9PSAicmVsaWdpb3VzIiB+ICJSZWxpZ2lvdXMgQ29udGVudCIsCiAgICBhaV9jb250ZW50X3R5cGVzID09ICJwb2xpdGljYWwiIH4gIlBvbGl0aWNhbCBDb250ZW50IiwKICAgIFRSVUUgfiAiT3RoZXIiCiAgKSkgJT4lCiAgY291bnQocmF0aW5nLCBjb250ZW50X2NhdGVnb3J5LCBuYW1lID0gIm1vZGlmaWNhdGlvbl9jb3VudCIsIHNvcnQgPSBUUlVFKSAlPiUKICBncm91cF9ieShyYXRpbmcpICU+JQogIG11dGF0ZShwZXJjZW50YWdlID0gbW9kaWZpY2F0aW9uX2NvdW50IC8gc3VtKG1vZGlmaWNhdGlvbl9jb3VudCkpICU+JQogIHVuZ3JvdXAoKQoKY29tbW9uX3R5cGVzIDwtIHJhdGluZ19icmVha2Rvd24gJT4lCiAgZmlsdGVyKGNvbnRlbnRfY2F0ZWdvcnkgIT0gIk90aGVyIikgJT4lCiAgZ3JvdXBfYnkoY29udGVudF9jYXRlZ29yeSkgJT4lCiAgc3VtbWFyaXNlKHRvdGFsID0gc3VtKG1vZGlmaWNhdGlvbl9jb3VudCksIC5ncm91cHMgPSAnZHJvcCcpICU+JQogIHB1bGwoY29udGVudF9jYXRlZ29yeSkKCnJhdGluZ19icmVha2Rvd24gJT4lCiAgZmlsdGVyKGNvbnRlbnRfY2F0ZWdvcnkgJWluJSBjb21tb25fdHlwZXMpICU+JQogIGdncGxvdChhZXMoCiAgICB4ID0gcGVyY2VudGFnZSwKICAgIHkgPSBmY3RfcmVvcmRlcihjb250ZW50X2NhdGVnb3J5LCBwZXJjZW50YWdlLCAuZGVzYyA9IEZBTFNFKSwKICAgIGZpbGwgPSByYXRpbmcKICApKSArCiAgZ2VvbV9jb2woY29sb3IgPSAid2hpdGUiLCBsaW5ld2lkdGggPSAwLjUpICsKICBmYWNldF93cmFwKH5yYXRpbmcsIHNjYWxlcyA9ICJmcmVlX3kiLCBuY29sID0gMykgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwoCiAgICB2YWx1ZXMgPSBjKCJVIiA9IHdlc19jb2xvcnNbMV0sICJVQSIgPSB3ZXNfY29sb3JzWzJdLCAiQSIgPSB3ZXNfY29sb3JzWzNdKQogICkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJDZW5zb3JzaGlwIHJlYXNvbnMgYnkgZmlsbSByYXRpbmciLAogICAgc3VidGl0bGUgPSAiUHJvcG9ydGlvbmFsIGJyZWFrZG93biBvZiBtb2RpZmljYXRpb24gcmVhc29ucyB3aXRoaW4gZWFjaCBmaWxtIHJhdGluZyBjYXRlZ29yeS4iLAogICAgeCA9ICIlIG9mIGFsbCBtb2RpZmljYXRpb25zIGZvciB0aGlzIHJhdGluZyIsCiAgICB5ID0gTlVMTAogICkgKwogIHRoZW1lX2NiZmMoKSArCiAgdGhlbWUoCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgZmFjZSA9ICJib2xkIiwgY29sb3IgPSAiZ3JheTIwIiwgbWFyZ2luID0gbWFyZ2luKHQgPSA1LCBiID0gMTApKSwKICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JheTkwIiwgbGluZXR5cGUgPSAiZG90dGVkIiksCiAgICBwYW5lbC5zcGFjaW5nLnggPSB1bml0KDIsICJsaW5lcyIpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiCiAgKQoKd3JpdGVfanNvbihyYXRpbmdfYnJlYWtkb3duLCAicmF0aW5nX2JyZWFrZG93bi5qc29uIiwgcHJldHR5ID0gVFJVRSwgYXV0b191bmJveCA9IFRSVUUpCmBgYAoKIyMgQXZlcmFnZSBDdXQgVGltZSBieSBSZWdpb25hbCBPZmZpY2UKCkRpZmZlcmVudCByZWdpb25hbCBvZmZpY2VzIG9mIHRoZSBDQkZDIG1heSBhcHBseSBjZW5zb3JzaGlwIHN0YW5kYXJkcyBkaWZmZXJlbnRseS4gSGVyZSwgd2UgY2FsY3VsYXRlIHRoZSBhdmVyYWdlIHRvdGFsIHRpbWUgbW9kaWZpZWQgcGVyIGZpbG0gZm9yIGVhY2ggbWFqb3Igb2ZmaWNlLiBXZSBmaWx0ZXIgb3V0IGV4dHJlbWUgb3V0bGllcnMgKGZpbG1zIHdpdGggbW9yZSB0aGFuIDMwIG1pbnV0ZXMgb2YgY3V0cykgYW5kIG9ubHkgaW5jbHVkZSBvZmZpY2VzIHRoYXQgaGF2ZSBjZXJ0aWZpZWQgYSBzdWZmaWNpZW50IG51bWJlciBvZiBmaWxtcyAoYXQgbGVhc3QgNTApLgoKYGBge3IgY3V0cy1ieS1vZmZpY2Utc3RhdHN9CmZpbG1fc3VtbWFyeSA8LSBkYXRhICU+JQogIGZpbHRlcighaXMubmEob2ZmaWNlKSAmICFzdHJfZGV0ZWN0KG9mZmljZSwgIlxcLm1wNCQiKSkgJT4lCiAgZ3JvdXBfYnkoaWQsIG1vdmllX25hbWUsIG9mZmljZSkgJT4lCiAgc3VtbWFyaXNlKAogICAgdG90YWxfc2VjcyA9IHN1bSh0b3RhbF9tb2RpZmllZF90aW1lX3NlY3MsIG5hLnJtID0gVFJVRSksCiAgICAuZ3JvdXBzID0gJ2Ryb3AnCiAgKSAlPiUKICBmaWx0ZXIodG90YWxfc2VjcyA+IDAsIHRvdGFsX3NlY3MgPCAxODAwKQoKb2ZmaWNlX3N0YXRzIDwtIGZpbG1fc3VtbWFyeSAlPiUKICBncm91cF9ieShvZmZpY2UpICU+JQogIGZpbHRlcihuKCkgPj0gNTApICU+JQogIHN1bW1hcmlzZSgKICAgIGZpbG1fY291bnQgPSBuKCksCiAgICBtZWFuX3RvdGFsX3NlY3MgPSBtZWFuKHRvdGFsX3NlY3MsIG5hLnJtID0gVFJVRSksCiAgICBzZSA9IHNkKHRvdGFsX3NlY3MsIG5hLnJtID0gVFJVRSkgLyBzcXJ0KG4oKSksCiAgICBjaV9sb3dlcl9zZWNzID0gcG1heCgwLCBtZWFuX3RvdGFsX3NlY3MgLSAxLjk2ICogc2UpLAogICAgY2lfdXBwZXJfc2VjcyA9IG1lYW5fdG90YWxfc2VjcyArIDEuOTYgKiBzZSwKICAgIC5ncm91cHMgPSAnZHJvcCcKICApICU+JQogIGFycmFuZ2UoZGVzYyhtZWFuX3RvdGFsX3NlY3MpKQoKd3JpdGVfanNvbihvZmZpY2Vfc3RhdHMsICJjdXRzX2J5X29mZmljZS5qc29uIiwgcHJldHR5ID0gVFJVRSwgYXV0b191bmJveCA9IFRSVUUpCgpzdW1tYXJ5X3RhYmxlIDwtIG9mZmljZV9zdGF0cyAlPiUKICBtdXRhdGUoCiAgICBgQXZlcmFnZSBUaW1lYCA9IGZvcm1hdF9zZWNvbmRzKG1lYW5fdG90YWxfc2VjcyksCiAgICBgOTUlIENJIExvd2VyYCA9IGZvcm1hdF9zZWNvbmRzKGNpX2xvd2VyX3NlY3MpLAogICAgYDk1JSBDSSBVcHBlcmAgPSBmb3JtYXRfc2Vjb25kcyhjaV91cHBlcl9zZWNzKQogICkgJT4lCiAgc2VsZWN0KAogICAgT2ZmaWNlID0gb2ZmaWNlLAogICAgYEZpbG1zIEFuYWx5emVkYCA9IGZpbG1fY291bnQsCiAgICBgQXZlcmFnZSBUaW1lYCwKICAgIGA5NSUgQ0kgTG93ZXJgLAogICAgYDk1JSBDSSBVcHBlcmAKICApCgpzdW1tYXJ5X3RhYmxlICU+JQogIGd0KCkgJT4lCiAgdGFiX2hlYWRlcigKICAgIHRpdGxlID0gIkF2ZXJhZ2UgTW9kaWZpY2F0aW9uIFRpbWUgcGVyIEZpbG0gYnkgQ0JGQyBSZWdpb25hbCBPZmZpY2UiLAogICAgc3VidGl0bGUgPSAiQW5hbHlzaXMgb2Ygb2ZmaWNlcyB3aXRoIGF0IGxlYXN0IDUwIGNlcnRpZmllZCBmaWxtcyIKICApICU+JQogIHRhYl9zdHlsZSgKICAgIHN0eWxlID0gbGlzdCgKICAgICAgY2VsbF9maWxsKGNvbG9yID0gd2VzX2NvbG9yc1sxXSwgYWxwaGEgPSAwLjMpLAogICAgICBjZWxsX3RleHQod2VpZ2h0ID0gImJvbGQiKQogICAgKSwKICAgIGxvY2F0aW9ucyA9IGNlbGxzX2NvbHVtbl9sYWJlbHMoKQogICkgJT4lCiAgdGFiX3N0eWxlKAogICAgc3R5bGUgPSBjZWxsX3RleHQoYWxpZ24gPSAiY2VudGVyIiksCiAgICBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSBjKGBGaWxtcyBBbmFseXplZGAsIGBBdmVyYWdlIFRpbWVgLCBgOTUlIENJIExvd2VyYCwgYDk1JSBDSSBVcHBlcmApKQogICkgJT4lCiAgY29sc19hbGlnbigKICAgIGFsaWduID0gImxlZnQiLAogICAgY29sdW1ucyA9IE9mZmljZQogICkgJT4lCiAgdGFiX29wdGlvbnMoCiAgICB0YWJsZS5mb250Lm5hbWVzID0gIkF0a2luc29uIEh5cGVybGVnaWJsZSIsCiAgICBoZWFkaW5nLnRpdGxlLmZvbnQuc2l6ZSA9IDE2LAogICAgaGVhZGluZy5zdWJ0aXRsZS5mb250LnNpemUgPSAxMiwKICAgIGNvbHVtbl9sYWJlbHMuZm9udC5zaXplID0gMTIsCiAgICB0YWJsZS5mb250LnNpemUgPSAxMQogICkKYGBgCgojIyBUcmVuZHMgaW4gQ2Vuc29yc2hpcCBDb250ZW50IFR5cGVzCgpIYXZlIHRoZSByZWFzb25zIGZvciBmaWxtIGNlbnNvcnNoaXAgY2hhbmdlZCBvdmVyIHRpbWU/IFRoaXMgYW5hbHlzaXMgdHJhY2tzIHRoZSBjaGFuZ2VzIGluIGRpZmZlcmVudCBtb2RpZmljYXRpb24gdHlwZXMgKFZpb2xlbmNlLCBQcm9mYW5pdHksIFNleHVhbCBDb250ZW50LCBldGMuKSBvbiBhIG1vbnRobHkgYmFzaXMuCgpGb3IgZWFjaCBjYXRlZ29yeSwgd2UgY2FsY3VsYXRlIGl0cyBkZXZpYXRpb24gZnJvbSBpdHMgb3duIGhpc3RvcmljYWwgYXZlcmFnZSAodGhlICJiYXNlbGluZSIpLiBUaGlzIG1ldGhvZCBjbGVhcmx5IHNob3dzIHBlcmlvZHMgd2hlbiBhIGNlcnRhaW4gdHlwZSBvZiBjb250ZW50IHdhcyBjZW5zb3JlZCBtb3JlIG9yIGxlc3MgZnJlcXVlbnRseSB0aGFuIHVzdWFsLiBXZSBhbHNvIGFwcGx5IGEgMy1tb250aCBtb3ZpbmcgYXZlcmFnZSB0byBzbW9vdGggb3V0IHNob3J0LXRlcm0gbm9pc2UgYW5kIHJldmVhbCB0aGUgdW5kZXJseWluZyB0cmVuZC4KCmBgYHtyIGNvbnRlbnQtdHJlbmRzLWNoYXJ0fQppbnRlcnBvbGF0ZV9hdF96ZXJvIDwtIGZ1bmN0aW9uKGRmKSB7CiAgc2lnbl9jaGFuZ2UgPC0gd2hpY2goZGlmZihzaWduKGRmJGRldmlhdGlvbl9wY3Rfc21vb3RoKSkgIT0gMCkKICBpZiAobGVuZ3RoKHNpZ25fY2hhbmdlKSA9PSAwKSByZXR1cm4oZGYpCiAgCiAgaW50ZXJwb2xhdGVkIDwtIG1hcF9kZihzaWduX2NoYW5nZSwgfnsKICAgIHNsaWNlIDwtIGRmWy54OigueCArIDEpLCBdCiAgICB6ZXJvX2Nyb3NzX2RhdGUgPC0gYXBwcm94KHNsaWNlJGRldmlhdGlvbl9wY3Rfc21vb3RoLCBhcy5udW1lcmljKHNsaWNlJHllYXJfbW9udGgpLCB4b3V0ID0gMCkkeQogICAgaWYgKGlzLm5hKHplcm9fY3Jvc3NfZGF0ZSkpIHJldHVybih0aWJibGUoKSkKICAgIHRpYmJsZSgKICAgICAgeWVhcl9tb250aCA9IGFzLkRhdGUoemVyb19jcm9zc19kYXRlLCBvcmlnaW4gPSAiMTk3MC0wMS0wMSIpLAogICAgICBkZXZpYXRpb25fcGN0X3Ntb290aCA9IDAsCiAgICAgIGFib3ZlX2Jhc2VsaW5lID0gc2xpY2UkYWJvdmVfYmFzZWxpbmVbMl0sCiAgICAgIGNvbnRlbnRfdHlwZSA9IHNsaWNlJGNvbnRlbnRfdHlwZVsxXSwKICAgICAgYmFzZWxpbmVfcmF0ZSA9IHNsaWNlJGJhc2VsaW5lX3JhdGVbMV0KICAgICkKICB9KQogIAogIGJpbmRfcm93cyhkZiwgaW50ZXJwb2xhdGVkKSAlPiUgYXJyYW5nZSh5ZWFyX21vbnRoKQp9CgpjaGFydF9kYXRhIDwtIGRhdGEgJT4lCiAgbXV0YXRlKAogICAgeWVhcl9tb250aCA9IGZsb29yX2RhdGUoY2VydF9kYXRlLCAibW9udGgiKSwKICAgIGNvbnRlbnRfdHlwZSA9IGNhc2Vfd2hlbigKICAgICAgYWlfY29udGVudF90eXBlcyAlaW4lIGMoInNleHVhbF9leHBsaWNpdCIsICJzZXh1YWxfc3VnZ2VzdGl2ZSIpIH4gIlNleHVhbCBDb250ZW50IiwKICAgICAgYWlfY29udGVudF90eXBlcyA9PSAicHJvZmFuaXR5IiB+ICJQcm9mYW5pdHkiLAogICAgICBhaV9jb250ZW50X3R5cGVzID09ICJ2aW9sZW5jZSIgfiAiVmlvbGVuY2UiLAogICAgICBhaV9jb250ZW50X3R5cGVzID09ICJzdWJzdGFuY2UiIH4gIlN1YnN0YW5jZSBVc2UiLAogICAgICBhaV9jb250ZW50X3R5cGVzID09ICJyZWxpZ2lvdXMiIH4gIlJlbGlnaW91cyBDb250ZW50IiwKICAgICAgYWlfY29udGVudF90eXBlcyA9PSAicG9saXRpY2FsIiB+ICJQb2xpdGljYWwgQ29udGVudCIsCiAgICAgIFRSVUUgfiBOQV9jaGFyYWN0ZXJfCiAgICApCiAgKSAlPiUKICBmaWx0ZXIoIWlzLm5hKGNvbnRlbnRfdHlwZSkpICU+JQogIGdyb3VwX2J5KHllYXJfbW9udGgsIGNvbnRlbnRfdHlwZSkgJT4lCiAgc3VtbWFyaXNlKGZpbG1zX3dpdGhfbW9kcyA9IG5fZGlzdGluY3QoY2VydGlmaWNhdGVfaWQpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBsZWZ0X2pvaW4oCiAgICBkYXRhICU+JQogICAgICBtdXRhdGUoeWVhcl9tb250aCA9IGZsb29yX2RhdGUoY2VydF9kYXRlLCAibW9udGgiKSkgJT4lCiAgICAgIGdyb3VwX2J5KHllYXJfbW9udGgpICU+JQogICAgICBzdW1tYXJpc2UodG90YWxfZmlsbXMgPSBuX2Rpc3RpbmN0KGNlcnRpZmljYXRlX2lkKSksCiAgICBieSA9ICJ5ZWFyX21vbnRoIgogICkgJT4lCiAgbXV0YXRlKHJhdGUgPSBmaWxtc193aXRoX21vZHMgLyB0b3RhbF9maWxtcykgJT4lCiAgZmlsdGVyKHRvdGFsX2ZpbG1zID49IDEwKSAlPiUKICBncm91cF9ieShjb250ZW50X3R5cGUpICU+JQogIGFycmFuZ2UoeWVhcl9tb250aCkgJT4lCiAgbXV0YXRlKAogICAgYmFzZWxpbmVfcmF0ZSA9IG1lYW4ocmF0ZSksCiAgICBkZXZpYXRpb25fcGN0ID0gKHJhdGUgLSBiYXNlbGluZV9yYXRlKSAvIGJhc2VsaW5lX3JhdGUgKiAxMDAsCiAgICBkZXZpYXRpb25fcGN0X3Ntb290aCA9IHpvbzo6cm9sbG1lYW4oZGV2aWF0aW9uX3BjdCwgayA9IDMsIGZpbGwgPSBOQSwgYWxpZ24gPSAiY2VudGVyIiksCiAgICBhYm92ZV9iYXNlbGluZSA9IGlmZWxzZShpcy5uYShkZXZpYXRpb25fcGN0X3Ntb290aCksIE5BLCBkZXZpYXRpb25fcGN0X3Ntb290aCA+IDApCiAgKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKCFpcy5uYShkZXZpYXRpb25fcGN0X3Ntb290aCkpICU+JQogIG11dGF0ZShjb250ZW50X3R5cGUgPSBmY3RfcmVvcmRlcihjb250ZW50X3R5cGUsIGJhc2VsaW5lX3JhdGUsIC5kZXNjID0gVFJVRSkpICU+JQogIGdyb3VwX2J5KGNvbnRlbnRfdHlwZSkgJT4lCiAgZ3JvdXBfbW9kaWZ5KH4gaW50ZXJwb2xhdGVfYXRfemVybygueCkpICU+JQogIHVuZ3JvdXAoKQoKZ2dwbG90KGNoYXJ0X2RhdGEsIGFlcyh4ID0geWVhcl9tb250aCwgeSA9IGRldmlhdGlvbl9wY3Rfc21vb3RoLCBjb2xvciA9IGFib3ZlX2Jhc2VsaW5lLCBncm91cCA9IDEpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAiZ3JleTQwIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fbGluZShsaW5ld2lkdGggPSAxLjIpICsKICBmYWNldF93cmFwKH5jb250ZW50X3R5cGUsIG5jb2wgPSAzKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKAogICAgdmFsdWVzID0gYygiVFJVRSIgPSB3ZXNfY29sb3JzWzVdLCAiRkFMU0UiID0gd2VzX2NvbG9yc1sxXSksCiAgICBsYWJlbHMgPSBjKCJCZWxvdyBCYXNlbGluZSIsICJBYm92ZSBCYXNlbGluZSIpLAogICAgbmFtZSA9IE5VTEwKICApICsKICBzY2FsZV94X2RhdGUoCiAgICBkYXRlX2xhYmVscyA9ICInJXkiLAogICAgZGF0ZV9icmVha3MgPSAiMiB5ZWFycyIsCiAgICBleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMC4wMiwgMC4wMikpCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKAogICAgbGFiZWxzID0gZnVuY3Rpb24oeCkgcGFzdGUwKGlmZWxzZSh4ID49IDAsICIrIiwgIiIpLCByb3VuZCh4LCAwKSwgIiUiKQogICkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJDZW5zb3JzaGlwIFBhdHRlcm5zIHZzLiBIaXN0b3JpY2FsIEF2ZXJhZ2UiLAogICAgY2FwdGlvbiA9ICJOb3RlOiBEYXNoZWQgbGluZSBpcyB0aGUgYmFzZWxpbmUgYXZlcmFnZSBmb3IgdGhhdCBjYXRlZ29yeS4gUmVkIGluZGljYXRlcyBtb250aHMgd2l0aCBhYm92ZS1hdmVyYWdlIGNlbnNvcnNoaXAgcmF0ZXM7IGJsdWUgaXMgYmVsb3ctYXZlcmFnZS5cbkEgMy1tb250aCBtb3ZpbmcgYXZlcmFnZSBoYXMgYmVlbiBhcHBsaWVkIHRvIHNtb290aCB0cmVuZHMuIFNvdXJjZTogQ2VudHJhbCBCb2FyZCBvZiBGaWxtIENlcnRpZmljYXRpb24uIiwKICAgIHggPSBOVUxMLAogICAgeSA9ICJEZXZpYXRpb24gZnJvbSBCYXNlbGluZSIKICApICsKICB0aGVtZV9jYmZjKCkgKwogIHRoZW1lKAogICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCBjb2xvciA9ICJncmV5NTAiLCBoanVzdCA9IDAsIG1hcmdpbiA9IG1hcmdpbih0ID0gMTYpKSwKICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JleTkwIiwgbGluZXdpZHRoID0gMC40KSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iCiAgKQoKd3JpdGVfanNvbihjaGFydF9kYXRhLCAiY29udGVudF90cmVuZHMuanNvbiIsIHByZXR0eSA9IFRSVUUsIGF1dG9fdW5ib3ggPSBUUlVFKQpgYGAKCiMjIERpc3RyaWJ1dGlvbiBvZiBNb2RpZmljYXRpb24gRHVyYXRpb25zCgpUaGlzIGhpc3RvZ3JhbSBzaG93cyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRvdGFsIG1vZGlmaWNhdGlvbiB0aW1lcyBmb3IgZmlsbXMgdGhhdCBoYWQgYXQgbGVhc3Qgb25lIGN1dC4gQXBwcm94aW1hdGVseSBoYWxmIG9mIHRoZSBmaWxtcyBpbiB0aGUgZGF0YXNldCBoYXZlICd6ZXJvIHNlY29uZHMnIG9mIGVkaXRzIChtZWFuaW5nIG1vZGlmaWNhdGlvbnMgbWlnaHQgaGF2ZSBiZWVuIG1hZGUgYnV0IHRoZXkgd2VyZSBub3QgbG9nZ2VkIHdpdGggYSBkdXJhdGlvbiBvZiBlZGl0KTsgdGhpcyBjaGFydCBmb2N1c2VzIG9ubHkgb24gdGhvc2UgdGhhdCBoYXZlIGR1cmF0aW9uIHZhbHVlcy4KCmBgYHtyIGR1cmF0aW9uLWRpc3RyaWJ1dGlvbi1jaGFydH0KZmlsbV9kYXRhIDwtIGRhdGEgJT4lCiAgZ3JvdXBfYnkoaWQpICU+JQogIHN1bW1hcmlzZSgKICAgIHRvdGFsX21vZGlmaWVkX3RpbWVfc2VjcyA9IHN1bSh0b3RhbF9tb2RpZmllZF90aW1lX3NlY3MsIG5hLnJtID0gVFJVRSksCiAgICAuZ3JvdXBzID0gJ2Ryb3AnCiAgKQoKdG90YWxfZmlsbXMgPC0gbnJvdyhmaWxtX2RhdGEpCnBlcmNlbnRfemVybyA8LSBtZWFuKGZpbG1fZGF0YSR0b3RhbF9tb2RpZmllZF90aW1lX3NlY3MgPT0gMCwgbmEucm0gPSBUUlVFKQpmaWxtX2RhdGFfcG9zaXRpdmUgPC0gZmlsbV9kYXRhICU+JSBmaWx0ZXIodG90YWxfbW9kaWZpZWRfdGltZV9zZWNzID4gMCkKbWVkaWFuX3ZhbF9wb3NpdGl2ZSA8LSBtZWRpYW4oZmlsbV9kYXRhX3Bvc2l0aXZlJHRvdGFsX21vZGlmaWVkX3RpbWVfc2VjcykKCnBfZGlzdCA8LSBnZ3Bsb3QoZmlsbV9kYXRhX3Bvc2l0aXZlLCBhZXMoeCA9IHRvdGFsX21vZGlmaWVkX3RpbWVfc2VjcykpICsKICBnZW9tX2hpc3RvZ3JhbSgKICAgIGFlcyh5ID0gYWZ0ZXJfc3RhdChjb3VudCkgLyB0b3RhbF9maWxtcyAqIDEwMCksCiAgICBmaWxsID0gd2VzX2NvbG9yc1syXSwKICAgIGJpbnMgPSA0MCwKICAgIGJvdW5kYXJ5ID0gMAogICkgKwogIGdlb21fdmxpbmUoCiAgICB4aW50ZXJjZXB0ID0gbWVkaWFuX3ZhbF9wb3NpdGl2ZSwKICAgIGxpbmV0eXBlID0gImRhc2hlZCIsCiAgICBjb2xvciA9ICJncmF5MjAiLAogICAgbGluZXdpZHRoID0gMC44CiAgKSArCiAgIyBVc2UgYSBsb2cxMCBzY2FsZSBvbiB0aGUgeC1heGlzIGJlY2F1c2UgdGhlIGRhdGEgaXMgaGlnaGx5IHNrZXdlZC4KICBzY2FsZV94X2xvZzEwKAogICAgYnJlYWtzID0gYygxLCAxMCwgNjAsIDMwMCwgMTgwMCksCiAgICBsYWJlbHMgPSBjKCIxcyIsICIxMHMiLCAiMW0iLCAiNW0iLCAiMzBtIikKICApICsKICBzY2FsZV95X2NvbnRpbnVvdXMoCiAgICBleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4wNSkpLAogICAgbGFiZWxzID0gcGVyY2VudF9mb3JtYXQoc2NhbGUgPSAxKQogICkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgTW9kaWZpY2F0aW9uIFRpbWVzIiwKICAgIHN1YnRpdGxlID0gc3RyX2dsdWUoIkNvbXBhcmluZyB0b3RhbCBtb2RpZmljYXRpb24gdGltZSBmb3IgZmlsbXMgd2l0aCBhdCBsZWFzdCBvbmUgY3V0LgogICAgICAgICAgICAgICAgICAgICAgICBUaGlzIGNoYXJ0IGV4Y2x1ZGVzIHRoZSB7cGVyY2VudChwZXJjZW50X3plcm8sIGFjY3VyYWN5PTEpfSBvZiBmaWxtcyB3aXRoIHplcm8gbW9kaWZpY2F0aW9ucy4iKSwKICAgIHggPSAiVG90YWwgTW9kaWZpY2F0aW9uIFRpbWUgKExvZ2FyaXRobWljIFNjYWxlKSIsCiAgICB5ID0gIlBlcmNlbnQgb2YgQWxsIEZpbG1zIgogICkgKwogIHRoZW1lX2NiZmMoKSArCiAgdGhlbWUoCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkKICApCgpwcmludChwX2Rpc3QpCgojIEV4cG9ydCB0aGUgZGF0YSB1c2VkIGZvciB0aGUgaGlzdG9ncmFtIHRvIGEgSlNPTiBmaWxlLgojIFdlIHVzZSBnZ3Bsb3RfYnVpbGQoKSB0byBleHRyYWN0IHRoZSBjb21wdXRlZCBkYXRhIGZyb20gdGhlIHBsb3Qgb2JqZWN0LgpoaXN0X2RhdGFfZm9yX2V4cG9ydCA8LSBnZ3Bsb3RfYnVpbGQocF9kaXN0KSRkYXRhW1sxXV0gJT4lCiAgc2VsZWN0KHhfbWluID0geG1pbiwgeF9tYXggPSB4bWF4LCBjb3VudCwgeV9wZXJjZW50X3RvdGFsID0geSkKCmV4cG9ydF9kYXRhX2Rpc3QgPC0gbGlzdCgKICBoaXN0b2dyYW1fYmlucyA9IGhpc3RfZGF0YV9mb3JfZXhwb3J0LAogIHN0YXRpc3RpY3MgPSBsaXN0KAogICAgbWVkaWFuX3Bvc2l0aXZlX3NlY3MgPSBtZWRpYW5fdmFsX3Bvc2l0aXZlLAogICAgdG90YWxfZmlsbXMgPSB0b3RhbF9maWxtcywKICAgIHBlcmNlbnRfemVyb19tb2RzID0gcGVyY2VudF96ZXJvCiAgKSwKICBheGlzX2NvbmZpZyA9IGxpc3QoCiAgICBicmVha3MgPSBjKDEsIDEwLCA2MCwgMzAwLCAxODAwKSwKICAgIGxhYmVscyA9IGMoIjFzIiwgIjEwcyIsICIxbSIsICI1bSIsICIzMG0iKQogICkKKQoKd3JpdGVfanNvbihleHBvcnRfZGF0YV9kaXN0LCAiaGlzdG9ncmFtX2RhdGEuanNvbiIsIHByZXR0eSA9IFRSVUUsIGF1dG9fdW5ib3ggPSBUUlVFKQpgYGAKCiMjIElkZW50aWZ5aW5nIFRyZW5kaW5nIENlbnNvcnNoaXAgQ2F0ZWdvcmllcwoKVG8gZGV0ZXJtaW5lIHdoaWNoIGNlbnNvcnNoaXAgY2F0ZWdvcmllcyBhcmUgaW5jcmVhc2luZyBvciBkZWNyZWFzaW5nIG92ZXIgdGltZSwgd2UgdXNlIGEgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbC4KCkEgcG9zaXRpdmUgc2xvcGUgZnJvbSB0aGUgbW9kZWwgaW5kaWNhdGVzIGFuIGluY3JlYXNpbmcgdHJlbmQsIHdoaWxlIGEgbmVnYXRpdmUgc2xvcGUgaW5kaWNhdGVzIGEgZGVjcmVhc2luZyB0cmVuZC4gV2UgdGhlbiB2aXN1YWxpemUgdGhlIHRvcCB0aHJlZSBmYXN0ZXN0LWluY3JlYXNpbmcgYW5kIGZhc3Rlc3QtZGVjcmVhc2luZyBjYXRlZ29yaWVzIHNpbmNlIDIwMTguCgpUaGlzIGlzIGJhc2VkIG9uIFtKdWxpYSBTaWxnZSdzIGV4Y2VsbGVudCBhcnRpY2xlIGRlbW9uc3RyYXRpbmcgYSBzaW1pbGFyIHR5cGUgb2YgYW5hbHlzaXNdKGh0dHBzOi8vanVsaWFzaWxnZS5jb20vYmxvZy9yZWRkaXQtcmVzcG9uZHMvKS4KCmBgYHtyIHRyZW5kaW5nLWNhdGVnb3JpZXMtYW5hbHlzaXN9CmNhdGVnb3JpZXNfYnlfcXVhcnRlciA8LSBkYXRhICU+JQogIGZpbHRlcighaXMubmEoY2VydF9kYXRlKSwgIWlzLm5hKGFpX2NvbnRlbnRfdHlwZXMpLCBjZXJ0X2RhdGUgPj0gYXMuRGF0ZSgiMjAxOC0wMS0wMSIpKSAlPiUKICBtdXRhdGUocXVhcnRlciA9IGZsb29yX2RhdGUoY2VydF9kYXRlLCB1bml0ID0gIjMgbW9udGhzIikpICU+JQogIGNvdW50KHF1YXJ0ZXIsIGFpX2NvbnRlbnRfdHlwZXMsIG5hbWUgPSAiY2F0ZWdvcnlfY291bnQiKSAlPiUKICBncm91cF9ieShxdWFydGVyKSAlPiUKICBtdXRhdGUocXVhcnRlcl90b3RhbF9jdXRzID0gc3VtKGNhdGVnb3J5X2NvdW50KSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGdyb3VwX2J5KGFpX2NvbnRlbnRfdHlwZXMpICU+JQogIGZpbHRlcihzdW0oY2F0ZWdvcnlfY291bnQpID4gMTAwKSAlPiUKICB1bmdyb3VwKCkKCmNhdGVnb3J5X21vZGVscyA8LSBjYXRlZ29yaWVzX2J5X3F1YXJ0ZXIgJT4lCiAgbmVzdChkYXRhID0gLWFpX2NvbnRlbnRfdHlwZXMpICU+JQogICMgKHRvdGFsIC0gY2F0ZWdvcnkpIGFzIGEgZnVuY3Rpb24gb2YgdGltZSAocXVhcnRlcikuCiAgbXV0YXRlKAogICAgbW9kZWwgPSBtYXAoZGF0YSwgfiBnbG0oCiAgICAgIGNiaW5kKGNhdGVnb3J5X2NvdW50LCBxdWFydGVyX3RvdGFsX2N1dHMgLSBjYXRlZ29yeV9jb3VudCkgfiBxdWFydGVyLAogICAgICBkYXRhID0gLiwKICAgICAgZmFtaWx5ID0gImJpbm9taWFsIgogICAgKSkKICApCgpzbG9wZXMgPC0gY2F0ZWdvcnlfbW9kZWxzICU+JQogIG11dGF0ZSh0aWRpZWQgPSBtYXAobW9kZWwsIHRpZHkpKSAlPiUKICB1bm5lc3QodGlkaWVkKSAlPiUKICBmaWx0ZXIodGVybSA9PSAicXVhcnRlciIpICU+JQogIGFycmFuZ2UoZGVzYyhlc3RpbWF0ZSkpCgp0cmVuZHNfdG9fcGxvdCA8LSBiaW5kX3Jvd3MoCiAgc2xvcGVzICU+JSB0b3BfbigzLCBlc3RpbWF0ZSksCiAgc2xvcGVzICU+JSB0b3BfbigtMywgZXN0aW1hdGUpCikKCmdncGxvdCgKICBjYXRlZ29yaWVzX2J5X3F1YXJ0ZXIgJT4lIGlubmVyX2pvaW4odHJlbmRzX3RvX3Bsb3QsIGJ5ID0gImFpX2NvbnRlbnRfdHlwZXMiKSwKICBhZXMoeCA9IHF1YXJ0ZXIsIHkgPSBjYXRlZ29yeV9jb3VudCAvIHF1YXJ0ZXJfdG90YWxfY3V0cywgCiAgICAgIGNvbG9yID0gZmN0X3Jlb3JkZXIyKGFpX2NvbnRlbnRfdHlwZXMsIHF1YXJ0ZXIsIGNhdGVnb3J5X2NvdW50KSkKKSArCiAgZ2VvbV9saW5lKGFscGhhID0gMC44LCBsaW5ld2lkdGggPSAxLjIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBsaW5ld2lkdGggPSAwLjUpICsKICBmYWNldF93cmFwKH4gaWZlbHNlKGVzdGltYXRlID4gMCwgIkluY3JlYXNpbmcgVHJlbmRzIiwgIkRlY3JlYXNpbmcgVHJlbmRzIiksIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gd2VzX2NvbG9ycykgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJXaGljaCBDZW5zb3JzaGlwIENhdGVnb3JpZXMgSGF2ZSBUcmVuZGVkIFVwIG9yIERvd24/IiwKICAgIHN1YnRpdGxlID0gIlByb3BvcnRpb24gb2YgYWxsIG1vZGlmaWNhdGlvbnMgcGVyIHF1YXJ0ZXIgc2luY2UgMjAxOCwgd2l0aCBhIGxpbmVhciB0cmVuZGxpbmUuIiwKICAgIHggPSAiRGF0ZSBvZiBDZXJ0aWZpY2F0aW9uIiwKICAgIHkgPSAiUGVyY2VudCBvZiBBbGwgQ3V0cyBpbiBRdWFydGVyIiwKICAgIGNvbG9yID0gIkNvbnRlbnQgVHlwZSIKICApICsKICB0aGVtZV9jYmZjKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKIyBFeHBvcnQgdHJlbmRpbmcgY2F0ZWdvcmllcyBkYXRhCiMgQ3JlYXRlIGNsZWFuIHZlcnNpb24gb2YgdHJlbmRzX3RvX3Bsb3Qgd2l0aG91dCBtb2RlbCBvYmplY3RzCnRyZW5kc19jbGVhbiA8LSB0cmVuZHNfdG9fcGxvdCAlPiUgCiAgc2VsZWN0KGFpX2NvbnRlbnRfdHlwZXMsIGVzdGltYXRlLCBzdGQuZXJyb3IsIHN0YXRpc3RpYywgcC52YWx1ZSkKCnRyZW5kaW5nX2V4cG9ydCA8LSBsaXN0KAogIHNsb3BlcyA9IHNsb3BlcyAlPiUgc2VsZWN0KGFpX2NvbnRlbnRfdHlwZXMsIGVzdGltYXRlLCBzdGQuZXJyb3IsIHN0YXRpc3RpYywgcC52YWx1ZSksCiAgcXVhcnRlcmx5X2RhdGEgPSBjYXRlZ29yaWVzX2J5X3F1YXJ0ZXIgJT4lCiAgICBpbm5lcl9qb2luKHRyZW5kc19jbGVhbiwgYnkgPSAiYWlfY29udGVudF90eXBlcyIpICU+JQogICAgc2VsZWN0KHF1YXJ0ZXIsIGFpX2NvbnRlbnRfdHlwZXMsIGNhdGVnb3J5X2NvdW50LCBxdWFydGVyX3RvdGFsX2N1dHMsIAogICAgICAgICAgIGVzdGltYXRlLCBzdGQuZXJyb3IsIHN0YXRpc3RpYywgcC52YWx1ZSkKKQp3cml0ZV9qc29uKHRyZW5kaW5nX2V4cG9ydCwgInRyZW5kaW5nX2NhdGVnb3JpZXMuanNvbiIsIHByZXR0eSA9IFRSVUUsIGF1dG9fdW5ib3ggPSBUUlVFKQpgYGAKCiMjIEtleXdvcmQgQ28tb2NjdXJyZW5jZSBOZXR3b3JrCgpUaGlzIGFuYWx5c2lzIGV4cGxvcmVzIHdoaWNoIHRlcm1zIHRlbmQgdG8gYXBwZWFyIHRvZ2V0aGVyIHdpdGhpbiB0aGUgc2FtZSBmaWxtJ3MgbW9kaWZpY2F0aW9uIHJlY29yZHMuCgpXZSBjYWxjdWxhdGUgdGhlIHBhaXJ3aXNlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIDUwIG1vc3QgY29tbW9uIGtleXdvcmRzIGFuZCB2aXN1YWxpemUgdGhlIHJlc3VsdHMgYXMgYSBuZXR3b3JrIGdyYXBoLgoKKipUaGlzIGNvbnRhaW5zIGEgbG90IG9mIE5TRlcgc3R1ZmYsIGJ1dCBoaWRpbmcgaXQgd291bGQuLi5wcm9iYWJseSBkZWZlYXQgdGhlIHBvaW50KiouCgpgYGB7ciBjby1vY2N1cnJlbmNlLW5ldHdvcmt9CnJlZmVyZW5jZV93b3JkcyA8LSBkYXRhICU+JQogIGZpbHRlcighaXMubmEoYWlfcmVmZXJlbmNlKSkgJT4lCiAgbXV0YXRlKHdvcmQgPSBzdHJfc3BsaXQodG9sb3dlcihhaV9yZWZlcmVuY2UpLCAiXFx8IikpICU+JQogIHVubmVzdCh3b3JkKSAlPiUKICBmaWx0ZXIoIWlzLm5hKHdvcmQpLCAhc3RyX2RldGVjdCh3b3JkLCAidmlvbGVuY2V8c2NlbmV8dmlzdWFsfGRpYWxvZ3VlIikpICU+JQogIHNlbGVjdChpZCwgd29yZCkKCndvcmRfY291bnRzIDwtIHJlZmVyZW5jZV93b3JkcyAlPiUKICBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkKCndvcmRfcGFpcnMgPC0gcmVmZXJlbmNlX3dvcmRzICU+JQogIGZpbHRlcih3b3JkICVpbiUgKHdvcmRfY291bnRzICU+JSB0b3Bfbig1MCwgbikgJT4lIHB1bGwod29yZCkpKSAlPiUKICBwYWlyd2lzZV9jb3IoaXRlbSA9IHdvcmQsIGZlYXR1cmUgPSBpZCwgc29ydCA9IFRSVUUpCgp3b3JkX3BhaXJzICU+JQogIGZpbHRlcihjb3JyZWxhdGlvbiA+IDAuMDUpICU+JQogIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSgpICU+JQogIGdncmFwaChsYXlvdXQgPSAiZnIiKSArCiAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBjb3JyZWxhdGlvbiksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX25vZGVfcG9pbnQoY29sb3IgPSB3ZXNfY29sb3JzWzNdLCBzaXplID0gNSkgKwogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCByZXBlbCA9IFRSVUUpICsKICB0aGVtZV92b2lkKCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJXaGljaCBDZW5zb3JzaGlwIFRlcm1zIEFwcGVhciBUb2dldGhlcj8iLAogICAgc3VidGl0bGUgPSAiQ28tb2NjdXJyZW5jZSBuZXR3b3JrIG9mIHRoZSA1MCBtb3N0IGNvbW1vbiBrZXl3b3JkcyBpbiBDQkZDIG1vZGlmaWNhdGlvbiByZWNvcmRzLiIKICApCgojIEV4cG9ydCBjby1vY2N1cnJlbmNlIG5ldHdvcmsgZGF0YQpuZXR3b3JrX2V4cG9ydCA8LSBsaXN0KAogIHdvcmRfY291bnRzID0gd29yZF9jb3VudHMgJT4lIHRvcF9uKDUwLCBuKSwKICB3b3JkX3BhaXJzID0gd29yZF9wYWlycyAlPiUgZmlsdGVyKGNvcnJlbGF0aW9uID4gMC4wNSkKKQp3cml0ZV9qc29uKG5ldHdvcmtfZXhwb3J0LCAia2V5d29yZF9uZXR3b3JrLmpzb24iLCBwcmV0dHkgPSBUUlVFLCBhdXRvX3VuYm94ID0gVFJVRSkKYGBgCgojIyBNb3N0IEltcG9ydGFudCBLZXl3b3JkcyBieSBDYXRlZ29yeSAoVEYtSURGKQoKV2hpbGUgdGhlIG5ldHdvcmsgZ3JhcGggc2hvd3Mgd2hpY2ggd29yZHMgY28tb2NjdXIsIGl0IGRvZXNuJ3QgdGVsbCB1cyB3aGljaCB3b3JkcyBhcmUgbW9zdCBjaGFyYWN0ZXJpc3RpYyBvZiBhICpzcGVjaWZpYyBjZW5zb3JzaGlwIGNhdGVnb3J5Ki4gRm9yIHRoYXQsIHdlIHVzZSBhIG1ldHJpYyBjYWxsZWQgW1Rlcm0gRnJlcXVlbmN5LUludmVyc2UgRG9jdW1lbnQgRnJlcXVlbmN5IChURi1JREYpXShodHRwczovL3d3dy50aWR5dGV4dG1pbmluZy5jb20vdGZpZGYpLgoKVEYtSURGIGlkZW50aWZpZXMgd29yZHMgdGhhdCBhcmUgY29tbW9uIHdpdGhpbiBvbmUgY2F0ZWdvcnkgKGUuZy4sICJibG9vZCIgaW4gdGhlICJ2aW9sZW5jZSIgY2F0ZWdvcnkpIGJ1dCBhcmUgcmVsYXRpdmVseSByYXJlIGluIGFsbCBvdGhlciBjYXRlZ29yaWVzLgoKYGBge3IgdGZpZGYtYW5hbHlzaXN9CnJlZmVyZW5jZV90b2tlbnMgPC0gZGF0YSAlPiUKICBmaWx0ZXIoIWlzLm5hKGFpX3JlZmVyZW5jZSksICFpcy5uYShhaV9jb250ZW50X3R5cGVzKSkgJT4lCiAgc2VsZWN0KGFpX2NvbnRlbnRfdHlwZXMsIGFpX3JlZmVyZW5jZSkgJT4lCiAgbXV0YXRlKHdvcmQgPSBzdHJfc3BsaXQodG9sb3dlcihhaV9yZWZlcmVuY2UpLCAiXFx8IikpICU+JQogIHVubmVzdCh3b3JkKSAlPiUKICBmaWx0ZXIod29yZCAhPSAiIikKCnJlZmVyZW5jZV90ZmlkZiA8LSByZWZlcmVuY2VfdG9rZW5zICU+JQogIGNvdW50KGFpX2NvbnRlbnRfdHlwZXMsIHdvcmQsIHNvcnQgPSBUUlVFKSAlPiUKICBiaW5kX3RmX2lkZih0ZXJtID0gd29yZCwgZG9jdW1lbnQgPSBhaV9jb250ZW50X3R5cGVzLCBuID0gbikgJT4lCiAgYXJyYW5nZShkZXNjKHRmX2lkZikpCgp0b3BfdGVybXNfdGFibGUgPC0gcmVmZXJlbmNlX3RmaWRmICU+JQogIGdyb3VwX2J5KGFpX2NvbnRlbnRfdHlwZXMpICU+JQogIHNsaWNlX21heChvcmRlcl9ieSA9IHRmX2lkZiwgbiA9IDUpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoQ2F0ZWdvcnkgPSBhaV9jb250ZW50X3R5cGVzLCBUZXJtID0gd29yZCwgYFRGLUlERmAgPSB0Zl9pZGYpICU+JQogIGZpbHRlcihDYXRlZ29yeSAlaW4lIGMoInZpb2xlbmNlIiwgInByb2Zhbml0eSIsICJzZXh1YWxfc3VnZ2VzdGl2ZSIsICJzdWJzdGFuY2UiLCAicG9saXRpY2FsIiwgInJlbGlnaW91cyIpKQoKdG9wX3Rlcm1zX3RhYmxlICU+JQogIGd0KCkgJT4lCiAgdGFiX2hlYWRlcigKICAgIHRpdGxlID0gIk1vc3QgRGlzdGluY3RpdmUgS2V5d29yZHMgYnkgQ2Vuc29yc2hpcCBDYXRlZ29yeSIsCiAgICBzdWJ0aXRsZSA9ICJVc2luZyBUZXJtIEZyZXF1ZW5jeS1JbnZlcnNlIERvY3VtZW50IEZyZXF1ZW5jeSAoVEYtSURGKSBhbmFseXNpcyIKICApICU+JQogIGZtdF9udW1iZXIoCiAgICBjb2x1bW5zID0gYFRGLUlERmAsCiAgICBkZWNpbWFscyA9IDMKICApICU+JQogIHRhYl9zdHlsZSgKICAgIHN0eWxlID0gbGlzdCgKICAgICAgY2VsbF9maWxsKGNvbG9yID0gd2VzX2NvbG9yc1syXSwgYWxwaGEgPSAwLjMpLAogICAgICBjZWxsX3RleHQod2VpZ2h0ID0gImJvbGQiKQogICAgKSwKICAgIGxvY2F0aW9ucyA9IGNlbGxzX2NvbHVtbl9sYWJlbHMoKQogICkgJT4lCiAgdGFiX3N0eWxlKAogICAgc3R5bGUgPSBjZWxsX3RleHQodHJhbnNmb3JtID0gImNhcGl0YWxpemUiKSwKICAgIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IENhdGVnb3J5KQogICkgJT4lCiAgdGFiX3N0eWxlKAogICAgc3R5bGUgPSBjZWxsX3RleHQoc3R5bGUgPSAiaXRhbGljIiksCiAgICBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSBUZXJtKQogICkgJT4lCiAgY29sc19hbGlnbigKICAgIGFsaWduID0gImNlbnRlciIsCiAgICBjb2x1bW5zID0gYFRGLUlERmAKICApICU+JQogIHRhYl9vcHRpb25zKAogICAgdGFibGUuZm9udC5uYW1lcyA9ICJBdGtpbnNvbiBIeXBlcmxlZ2libGUiLAogICAgaGVhZGluZy50aXRsZS5mb250LnNpemUgPSAxNiwKICAgIGhlYWRpbmcuc3VidGl0bGUuZm9udC5zaXplID0gMTIsCiAgICBjb2x1bW5fbGFiZWxzLmZvbnQuc2l6ZSA9IDEyLAogICAgdGFibGUuZm9udC5zaXplID0gMTEsCiAgICByb3dfZ3JvdXAuZm9udC53ZWlnaHQgPSAiYm9sZCIKICApCgp3cml0ZV9qc29uKHJlZmVyZW5jZV90ZmlkZiAlPiUgc2xpY2VfaGVhZChuID0gMzAwKSwgInRmaWRmX2FuYWx5c2lzLmpzb24iLCBwcmV0dHkgPSBUUlVFLCBhdXRvX3VuYm94ID0gVFJVRSkKYGBgCgojIyBUb3AgQ2Vuc29yZWQgRmlsbXMgYnkgT2ZmaWNlCgpJZGVudGlmaWVzIHRoZSB0b3AgZmlsbXMgdGhhdCBoYWQgdGhlIG1vc3QgdGltZSByZW1vdmVkIGJ5IGVhY2ggbWFqb3IgQ0JGQyByZWdpb25hbCBvZmZpY2UuCgpgYGB7ciB0b3AtY2Vuc29yZWQtZmlsbXMtYnktb2ZmaWNlfQpmaWxtX2xldmVsX3N1bW1hcnkgPC0gZGF0YSAlPiUKICBmaWx0ZXIoIWlzLm5hKG9mZmljZSkgJiAhc3RyX2RldGVjdChvZmZpY2UsICJcXC5tcDQkIikpICU+JQogIGdyb3VwX2J5KGlkLCBtb3ZpZV9uYW1lLCBvZmZpY2UsIGxhbmd1YWdlLCBjZXJ0X2RhdGUsIGNlcnRfbm8pICU+JQogIHN1bW1hcmlzZSgKICAgIHRvdGFsX2N1dHMgPSBuKCksCiAgICB0b3RhbF90aW1lX3JlbW92ZWRfc2VjcyA9IHN1bSh0b3RhbF9tb2RpZmllZF90aW1lX3NlY3MsIG5hLnJtID0gVFJVRSksCiAgICAuZ3JvdXBzID0gJ2Ryb3AnCiAgKSAlPiUKICBmaWx0ZXIodG90YWxfdGltZV9yZW1vdmVkX3NlY3MgPiAwLCB0b3RhbF90aW1lX3JlbW92ZWRfc2VjcyA8IDE4MDApICU+JQogIG11dGF0ZSgKICAgIHllYXIgPSBtYXAyX2RibChjZXJ0X2RhdGUsIGNlcnRfbm8sIH4gZXh0cmFjdF95ZWFyKC54LCAueSkpLAogICAgY2xlYW5lZF9uYW1lID0gbWFwX2Nocihtb3ZpZV9uYW1lLCBjbGVhbl9uYW1lKSwKICAgIHNsdWcgPSBtYXAyX2NocihjbGVhbmVkX25hbWUsIHllYXIsIG1ha2Vfc2x1ZykKICApCgp0b3BfY2Vuc29yZWRfYnlfb2ZmaWNlIDwtIGZpbG1fbGV2ZWxfc3VtbWFyeSAlPiUKICBncm91cF9ieShvZmZpY2UpICU+JQogIGFycmFuZ2UoZGVzYyh0b3RhbF90aW1lX3JlbW92ZWRfc2VjcykpICU+JQogIHNsaWNlX2hlYWQobiA9IDEwKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKAogICAgZHVyYXRpb25fZm9ybWF0dGVkID0gZm9ybWF0X3NlY29uZHModG90YWxfdGltZV9yZW1vdmVkX3NlY3MpCiAgKSAlPiUKICBhcnJhbmdlKG9mZmljZSwgZGVzYyh0b3RhbF90aW1lX3JlbW92ZWRfc2VjcykpICU+JQogIHNlbGVjdChPZmZpY2UgPSBvZmZpY2UsIExhbmd1YWdlID0gbGFuZ3VhZ2UsIGBGaWxtIE5hbWVgID0gY2xlYW5lZF9uYW1lLCAKICAgICAgICAgYFRpbWUgUmVtb3ZlZGAgPSBkdXJhdGlvbl9mb3JtYXR0ZWQsIGBUb3RhbCBDdXRzYCA9IHRvdGFsX2N1dHMsIFNsdWcgPSBzbHVnKQoKZGlzcGxheV90YWJsZSA8LSB0b3BfY2Vuc29yZWRfYnlfb2ZmaWNlICU+JQogIHNlbGVjdCgtU2x1ZykKCmRpc3BsYXlfdGFibGUgJT4lCiAgZ3QoKSAlPiUKICB0YWJfaGVhZGVyKAogICAgdGl0bGUgPSAiVG9wIDEwIE1vc3QgQ2Vuc29yZWQgRmlsbXMgYnkgVGltZSBSZW1vdmVkIiwKICAgIHN1YnRpdGxlID0gIkZpbG1zIHdpdGggdGhlIGhpZ2hlc3QgbW9kaWZpY2F0aW9uIHRpbWVzIGZvciBlYWNoIHJlZ2lvbmFsIG9mZmljZSIKICApICU+JQogIHRhYl9zdHlsZSgKICAgIHN0eWxlID0gbGlzdCgKICAgICAgY2VsbF9maWxsKGNvbG9yID0gd2VzX2NvbG9yc1szXSwgYWxwaGEgPSAwLjMpLAogICAgICBjZWxsX3RleHQod2VpZ2h0ID0gImJvbGQiKQogICAgKSwKICAgIGxvY2F0aW9ucyA9IGNlbGxzX2NvbHVtbl9sYWJlbHMoKQogICkgJT4lCiAgdGFiX3N0eWxlKAogICAgc3R5bGUgPSBjZWxsX3RleHQoc3R5bGUgPSAiaXRhbGljIiksCiAgICBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSBgRmlsbSBOYW1lYCkKICApICU+JQogIGNvbHNfYWxpZ24oCiAgICBhbGlnbiA9ICJjZW50ZXIiLAogICAgY29sdW1ucyA9IGMoTGFuZ3VhZ2UsIGBUaW1lIFJlbW92ZWRgLCBgVG90YWwgQ3V0c2ApCiAgKSAlPiUKICBjb2xzX2FsaWduKAogICAgYWxpZ24gPSAibGVmdCIsCiAgICBjb2x1bW5zID0gYyhPZmZpY2UsIGBGaWxtIE5hbWVgKQogICkgJT4lCiAgdGFiX29wdGlvbnMoCiAgICB0YWJsZS5mb250Lm5hbWVzID0gIkF0a2luc29uIEh5cGVybGVnaWJsZSIsCiAgICBoZWFkaW5nLnRpdGxlLmZvbnQuc2l6ZSA9IDE2LAogICAgaGVhZGluZy5zdWJ0aXRsZS5mb250LnNpemUgPSAxMiwKICAgIGNvbHVtbl9sYWJlbHMuZm9udC5zaXplID0gMTIsCiAgICB0YWJsZS5mb250LnNpemUgPSAxMQogICkgJT4lCiAgdGFiX3N0eWxlKAogICAgc3R5bGUgPSBjZWxsX2JvcmRlcnMoCiAgICAgIHNpZGVzID0gYygidG9wIiwgImJvdHRvbSIpLAogICAgICBjb2xvciA9ICJsaWdodGdyYXkiLAogICAgICB3ZWlnaHQgPSBweCgxKQogICAgKSwKICAgIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoKQogICkKCiMgRXhwb3J0IHRvcCBjZW5zb3JlZCBmaWxtcyBkYXRhIHdpdGggc2x1ZyBpbmNsdWRlZAp3cml0ZV9qc29uKHRvcF9jZW5zb3JlZF9ieV9vZmZpY2UsICJ0b3BfY2Vuc29yZWRfZmlsbXMuanNvbiIsIHByZXR0eSA9IFRSVUUsIGF1dG9fdW5ib3ggPSBUUlVFKQpgYGAKCiMjIEZ1cnRoZXIgSW5mb3JtYXRpb24KCkZvciBtb3JlIGRldGFpbHMsIGludGVyYWN0aXZlIGNoYXJ0cywgYW5kIHRoZSBmdWxsIGV4cGxvcmVyLCBwbGVhc2UgdmlzaXQgb3VyIHByb2plY3Qgd2Vic2l0ZTogaHR0cHM6Ly9jYmZjLndhdGNoCgpUaGUgYW5hbHlzaXMgd2FzIGNvbmR1Y3RlZCBieSBBbWFuIEJoYXJnYXZhIGFuZCBWaXZlayBNYXR0aGV3IGZvciBEaWFncmFtIENoYXNpbmcuCgojIyMgSG93IHRvIENpdGUKCmBgYApCaGFyZ2F2YSwgQS4sIE1hdHRoZXcsIFYuLCAmIERpYWdyYW0gQ2hhc2luZy4gKDIwMjUpLiBBbmFseXppbmcgRmlsbSBDZW5zb3JzaGlwIGluIEluZGlhOiBDQkZDIFdhdGNoLiBSZXRyaWV2ZWQgZnJvbSBodHRwczovL2NiZmMud2F0Y2guCmBgYAoKKipCaWJUZVggRW50cnkqKgoKRm9yIHVzZSBpbiBMYVRlWCBkb2N1bWVudHMsIHlvdSBjYW4gdXNlIHRoZSBmb2xsb3dpbmcgQmliVGVYIGVudHJ5OgoKYGBgYmlidGV4CkBtaXNje0JoYXJnYXZhMjAyNUNCRkMsCiAgYXV0aG9yID0ge0JoYXJnYXZhLCBBbWFuIGFuZCBNYXR0aGV3LCBWaXZlayBhbmQge0RpYWdyYW0gQ2hhc2luZ319LAogIHRpdGxlICA9IHtBbmFseXppbmcgRmlsbSBDZW5zb3JzaGlwIGluIEluZGlhOiBDQkZDIFdhdGNofSwKICB5ZWFyICAgPSB7MjAyNX0sCiAgbW9udGggID0ge1NlcHRlbWJlcn0sCiAgaG93cHVibGlzaGVkID0ge1x1cmx7aHR0cHM6Ly9jYmZjLndhdGNofX0sCiAgbm90ZSAgID0ge0FuYWx5c2lzIGFuZCB2aXN1YWxpemF0aW9ucyBieSBEaWFncmFtIENoYXNpbmcuIExhc3QgYWNjZXNzZWQ6IFx0b2RheX0KfQpgYGA=